Railway Operation Simulator  v2.7.0
A railway simulator for Windows
InterfaceUnit.cpp
Go to the documentation of this file.
1 // InterfaceUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 
27 #include <Classes.hpp>
28 #include <Controls.hpp>
29 #include <StdCtrls.hpp>
30 #include <Forms.hpp>
31 #include <Buttons.hpp>
32 #include <ExtCtrls.hpp>
33 #include <Menus.hpp>
34 #include <Dialogs.hpp>
35 #include <Graphics.hpp>
36 #include <ComCtrls.hpp>
37 #include <fstream>
38 #include <vector>
39 #include <vcl.h>
40 #include <stdio.h>
41 #include <algorithm> //for sort
42 
43 #pragma hdrstop
44 // The above batch of include files above #pragma hdrstop appear in all .cpp files.
45 // They aren't all needed in each case but being together and identical they speed
46 // up compilation considerably (without ~14 min, with ~1 min!). They are used in
47 // conjunction with 'use pre-compiled headers' in the project compiler options.
48 
49 #include "InterfaceUnit.h"
50 #include "GraphicUnit.h"
51 #include "DisplayUnit.h"
52 #include "TextUnit.h"
53 #include "TrainUnit.h"
54 #include "Utilities.h"
55 #include "TrackUnit.h"
56 #include "AboutUnit.h"
57 #include <fstream>
58 #include <dirent.h>
59 #include <Filectrl.hpp> //to check whether directories exist
60 
61 // ---------------------------------------------------------------------------
62 #include <Vcl.HTMLHelpViewer.hpp> //added at v2.0.0 for access to the .chm help file
63 #pragma package(smart_init)
64 #pragma link "Vcl.HTMLHelpViewer" //added at v2.0.0 for access to the .chm help file
65 #pragma resource "*.dfm"
66 
68 
69 // Folder Names
70 const UnicodeString TInterface::RAILWAY_DIR_NAME = "Railways";
71 const UnicodeString TInterface::TIMETABLE_DIR_NAME = "Program timetables";
72 const UnicodeString TInterface::PERFLOG_DIR_NAME = "Performance logs";
73 const UnicodeString TInterface::SESSION_DIR_NAME = "Sessions";
74 const UnicodeString TInterface::IMAGE_DIR_NAME = "Images";
75 const UnicodeString TInterface::FORMATTEDTT_DIR_NAME = "Formatted timetables";
76 const UnicodeString TInterface::USERGRAPHICS_DIR_NAME = "Graphics";
77 
78 // ---------------------------------------------------------------------------
79 
80 __fastcall TInterface::TInterface(TComponent* Owner): TForm(Owner)
81 { // constructor
82  try
83  {
84  Screen->Cursor = TCursor(-11); // Hourglass
85  DirOpenError = false;
86  AllSetUpFlag = false; // flag to prevent MasterClock from being enabled when application activates if there has been an error during
87  // initial setup
88  // MasterClock->Enabled = false;//keep this stopped until all set up (no effect here as form not yet created, made false in object insp)
89  // Visible = false; //keep the Interface form invisible until all set up (no effect here as form not yet created, made false in object insp)
91  // use GNU Major/Minor/Patch version numbering system, change for each published modification, Dev x = interim internal
92  // development stages (don't show on published versions)
93 
94  // check for presence of directories, creation failure probably indicates that the
95  // working folder is read-only
96  CurDir = GetCurrentDir();
97  if(!DirectoryExists(RAILWAY_DIR_NAME))
98  {
99  if(!CreateDir(RAILWAY_DIR_NAME))
100  {
101  DirOpenError = true;
102  }
103  }
104  if(!DirectoryExists(TIMETABLE_DIR_NAME))
105  {
106  if(!CreateDir(TIMETABLE_DIR_NAME))
107  {
108  DirOpenError = true;
109  }
110  }
111  if(!DirectoryExists(PERFLOG_DIR_NAME))
112  {
113  if(!CreateDir(PERFLOG_DIR_NAME))
114  {
115  DirOpenError = true;
116  }
117  }
118  if(!DirectoryExists(SESSION_DIR_NAME))
119  {
120  if(!CreateDir(SESSION_DIR_NAME))
121  {
122  DirOpenError = true;
123  }
124  }
125  if(!DirectoryExists(IMAGE_DIR_NAME))
126  {
127  if(!CreateDir(IMAGE_DIR_NAME))
128  {
129  DirOpenError = true;
130  }
131  }
132  if(!DirectoryExists(FORMATTEDTT_DIR_NAME))
133  {
134  if(!CreateDir(FORMATTEDTT_DIR_NAME))
135  {
136  DirOpenError = true;
137  }
138  }
139  if(!DirectoryExists(USERGRAPHICS_DIR_NAME))
140  {
141  if(!CreateDir(USERGRAPHICS_DIR_NAME))
142  {
143  DirOpenError = true;
144  }
145  }
146  if(DirOpenError)
147  {
148  ShowMessage("Failed to create one or more of folders: " + RAILWAY_DIR_NAME + ", " + TIMETABLE_DIR_NAME + ", " + PERFLOG_DIR_NAME + ", " +
150  "program operation may be restricted");
151  }
152 
153  Application->HelpFile = AnsiString(CurDir + "\\Help.chm"); // added at v2.0.0 for .chm help file
154 
155  MainMenu1->AutoHotkeys = maManual; // Embarcadero mod: to suppress '&' inclusion for underlined characters in menu items
156  PopupMenu->AutoHotkeys = maManual; // as above
157 
158  Utilities = new TUtilities;
159  RailGraphics = new TRailGraphics();
160 
161  int DispW = (Screen->Width - 64) / 16; // will truncate down to a multiple of 16 OK here as screen dimensions are accurate
162  int DispH = (Screen->Height - 192) / 16; // Interface dimensions are 16 too wide & 14 short in height
163  MainScreen->Width = DispW * 16;
164  MainScreen->Height = DispH * 16;
165 
168  Utilities->ScreenElementWidth = DispW;
170  HiddenScreen = new TImage(Interface);
171  HiddenScreen->Width = MainScreen->Width;
172  HiddenScreen->Height = MainScreen->Height;
176  Track = new TTrack;
177  AllRoutes = new TAllRoutes;
182  SelectBitmap = new Graphics::TBitmap;
183  SelectBitmap->PixelFormat = pf8bit;
184  SelectBitmap->Transparent = true;
189  LengthWarningSentFlag = false;
190  PasteWarningSentFlag = false; //added at v2.6.0
191  FillSelectionMessageSentFlag = false; //added at v2.6.0
192  LCManualLowerBarriersMessageSent = false; //added at v2.6.0
193 
194  TrackInfoOnOffMenuItem->Caption = "Show"; // added here at v1.2.0 because dropped from ResetAll()
195  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status"; // changed at v2.0.0 so normally visible
196  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable"; // as above
197  ResetAll(0);
198 
199  TempTTFileName = "";
200 
205 
206  RouteFlashDuration = 0.0;
207  PointsFlashDuration = 0.0;
208 
209  FloatingLabel->Color = clB4G5R5;
210  TrackElementPanel->Color = clB5G5R4;
211  InfoPanel->Color = clB4G5R5;
212 
213  LoadUserGraphicDialog->InitialDir = CurDir + "\\" + USERGRAPHICS_DIR_NAME; //not changeable
214 
215  Utilities->RHSignalFlag = false; // new at v2.3.0 for RH signals, always left hand on startup
216  SigsOnLeftImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
217  SigsOnLeftImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
218  SigsOnLeftImage1->Transparent = true;
219  SigsOnLeftImage2->Transparent = true;
220  SigsOnLeftImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
221  SigsOnLeftImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
222  SigsOnRightImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
223  SigsOnRightImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
224  SigsOnRightImage1->Transparent = true;
225  SigsOnRightImage2->Transparent = true;
226  SigsOnRightImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
227  SigsOnRightImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
228 
229  SaveRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME; //default locations if not updated from Config.txt
230  LoadRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
231  TimetableDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
232  SaveTTDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
233  LoadSessionDialog->InitialDir = CurDir + "\\" + SESSION_DIR_NAME;
234 
235  std::ifstream ConfigFile((CurDir + "\\Config.txt").c_str()); //added at v2.6.0 to set save & load directories for railways, timetables & session & to
236  if(ConfigFile.fail()) //no Config file //replace Signal.hnd, Background.col and GNU
237  {
238  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
239  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
240  SigsOnLeftImage1->Visible = true;
241  SigsOnLeftImage2->Visible = true;
242  SigsOnRightImage1->Visible = false;
243  SigsOnRightImage2->Visible = false;
244  ShowMessage(
245  "This program is free software released under the terms of the GNU General Public License Version 3, as published by the Free Software Foundation. "
246  "It may be used or redistributed in accordance with that license and is released in the hope that it will be useful, but WITHOUT ANY WARRANTY; "
247  "without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details - "
248  "you should have received a copy along with this program but if not see <http://www.gnu.org/licenses/>.");
249  }
250  else
251  {
252  AnsiString ConfigStr = "";
253  do
254  {
255  Utilities->CheckAndReadFileString(ConfigFile, ConfigStr);
256  if(ConfigFile.eof())
257  {
258  break;
259  }
260  AnsiString ConfigValue = ConfigStr.SubString(9, ConfigStr.Length() - 8);
261  if(ConfigStr.SubString(1, 8) == "Signals=")
262  {
263  if(ConfigValue == "right")
264  {
265  RailGraphics->ConvertSignalsToOppositeHand(1); // always left hand initially when start program, toggles Utilities->RHSignalFlag
266  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
268  {
270  }
271  else
272  {
274  }
275  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
276  SigsOnLeftImage1->Visible = false;
277  SigsOnLeftImage2->Visible = false;
278  SigsOnRightImage1->Visible = true;
279  SigsOnRightImage2->Visible = true;
280  }
281  else
282  {
283  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
284  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
285  SigsOnLeftImage1->Visible = true;
286  SigsOnLeftImage2->Visible = true;
287  SigsOnRightImage1->Visible = false;
288  SigsOnRightImage2->Visible = false;
289  }
290  }
291  if(ConfigStr.SubString(1, 8) == "BgndCol=")
292  {
293  // pick up transparent colour from file if there is one & set it to the stored value if it's valid else set to black
294  Utilities->clTransparent = clB0G0R0; // default black background;
295  if(ConfigValue == "white")
296  {
297  Utilities->clTransparent = TColor(0xFFFFFF);
298  }
299  else if(ConfigValue == "blue")
300  {
301  Utilities->clTransparent = TColor(0x330000);
302  }
303  }
304  if(ConfigStr.SubString(1, 8) == "RLYLocn=")
305  {
306  if(DirectoryExists(ConfigValue)) //e;se stays as original directory
307  {
308  SaveRailwayDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
309  LoadRailwayDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
310  }
311  }
312  else if(ConfigStr.SubString(1, 8) == "TTBLocn=")
313  {
314  if(DirectoryExists(ConfigValue)) //e;se stays as original directory
315  {
316  TimetableDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
317  SaveTTDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
318  }
319  }
320  else if(ConfigStr.SubString(1, 8) == "SSNLocn=")
321  {
322  if(DirectoryExists(ConfigValue)) //e;se stays as original directory
323  {
324  LoadSessionDialog->InitialDir = ConfigStr.SubString(9, ConfigStr.Length() - 8);
325  }
326  }
327  }
328  while(!ConfigFile.eof());
329  ConfigFile.close();
330  }
331 
332  SpeedButton1->Glyph->LoadFromResourceName(0, "gl1");
333  SpeedButton2->Glyph->LoadFromResourceName(0, "gl2");
334  SpeedButton3->Glyph->LoadFromResourceName(0, "gl3");
335  SpeedButton4->Glyph->LoadFromResourceName(0, "gl4");
336  SpeedButton5->Glyph->LoadFromResourceName(0, "gl5");
337  SpeedButton6->Glyph->LoadFromResourceName(0, "gl6");
338  SpeedButton7->Glyph->LoadFromResourceName(0, "gl7");
339  SpeedButton8->Glyph->LoadFromResourceName(0, "gl8");
340  SpeedButton9->Glyph->LoadFromResourceName(0, "gl9");
341  SpeedButton10->Glyph->LoadFromResourceName(0, "gl10");
342  SpeedButton11->Glyph->LoadFromResourceName(0, "gl11");
343  SpeedButton12->Glyph->LoadFromResourceName(0, "gl12");
344  SpeedButton13->Glyph->LoadFromResourceName(0, "gl13");
345  SpeedButton14->Glyph->LoadFromResourceName(0, "gl14");
346  SpeedButton15->Glyph->LoadFromResourceName(0, "gl15");
347  SpeedButton16->Glyph->LoadFromResourceName(0, "gl16");
348  SpeedButton18->Glyph->LoadFromResourceName(0, "gl18");
349  SpeedButton19->Glyph->LoadFromResourceName(0, "gl19");
350  SpeedButton20->Glyph->LoadFromResourceName(0, "gl20");
351  SpeedButton21->Glyph->LoadFromResourceName(0, "gl21");
352  SpeedButton22->Glyph->LoadFromResourceName(0, "gl22");
353  SpeedButton23->Glyph->LoadFromResourceName(0, "gl23");
354  SpeedButton24->Glyph->LoadFromResourceName(0, "gl24");
355  SpeedButton25->Glyph->LoadFromResourceName(0, "gl25");
356  SpeedButton26->Glyph->LoadFromResourceName(0, "gl26");
357  SpeedButton27->Glyph->LoadFromResourceName(0, "gl27");
358  SpeedButton28->Glyph->LoadFromResourceName(0, "gl28");
359  SpeedButton29->Glyph->LoadFromResourceName(0, "gl29");
360  SpeedButton30->Glyph->LoadFromResourceName(0, "gl30");
361  SpeedButton31->Glyph->LoadFromResourceName(0, "gl31");
362  SpeedButton32->Glyph->LoadFromResourceName(0, "gl32");
363  SpeedButton33->Glyph->LoadFromResourceName(0, "gl33");
364  SpeedButton34->Glyph->LoadFromResourceName(0, "gl34");
365  SpeedButton35->Glyph->LoadFromResourceName(0, "gl35");
366  SpeedButton36->Glyph->LoadFromResourceName(0, "gl36");
367  SpeedButton37->Glyph->LoadFromResourceName(0, "gl37");
368  SpeedButton38->Glyph->LoadFromResourceName(0, "gl38");
369  SpeedButton39->Glyph->LoadFromResourceName(0, "gl39");
370  SpeedButton40->Glyph->LoadFromResourceName(0, "gl40");
371  SpeedButton41->Glyph->LoadFromResourceName(0, "gl41");
372  SpeedButton42->Glyph->LoadFromResourceName(0, "gl42");
373  SpeedButton43->Glyph->LoadFromResourceName(0, "gl43");
374  SpeedButton44->Glyph->LoadFromResourceName(0, "gl44");
375  SpeedButton45->Glyph->LoadFromResourceName(0, "gl45");
376  SpeedButton46->Glyph->LoadFromResourceName(0, "gl46");
377  SpeedButton47->Glyph->LoadFromResourceName(0, "gl47");
378  SpeedButton48->Glyph->LoadFromResourceName(0, "gl48");
379  SpeedButton49->Glyph->LoadFromResourceName(0, "gl49");
380  SpeedButton50->Glyph->LoadFromResourceName(0, "gl50");
381  SpeedButton51->Glyph->LoadFromResourceName(0, "gl51");
382  SpeedButton52->Glyph->LoadFromResourceName(0, "gl52");
383  SpeedButton53->Glyph->LoadFromResourceName(0, "gl53");
384  SpeedButton54->Glyph->LoadFromResourceName(0, "gl54");
385  SpeedButton55->Glyph->LoadFromResourceName(0, "gl55");
386  SpeedButton56->Glyph->LoadFromResourceName(0, "gl56");
387  SpeedButton57->Glyph->LoadFromResourceName(0, "gl57");
388  SpeedButton58->Glyph->LoadFromResourceName(0, "gl58");
389  SpeedButton59->Glyph->LoadFromResourceName(0, "gl59");
390  SpeedButton60->Glyph->LoadFromResourceName(0, "gl60");
391  SpeedButton61->Glyph->LoadFromResourceName(0, "gl61");
392  SpeedButton62->Glyph->LoadFromResourceName(0, "gl62");
393  SpeedButton63->Glyph->LoadFromResourceName(0, "gl63");
394  SpeedButton64->Glyph->LoadFromResourceName(0, "gl64");
395  SpeedButton65->Glyph->LoadFromResourceName(0, "gl65");
396  SpeedButton66->Glyph->LoadFromResourceName(0, "gl66");
397  SpeedButton67->Glyph->LoadFromResourceName(0, "gl67");
398  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68");
399  SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
400  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70");
401  SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
402  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72");
403  SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
404  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74");
405  SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
406  SpeedButton76->Glyph->LoadFromResourceName(0, "gl76");
407  SpeedButton77->Glyph->LoadFromResourceName(0, "gl77");
408  SpeedButton78->Glyph->LoadFromResourceName(0, "gl78");
409  SpeedButton79->Glyph->LoadFromResourceName(0, "gl79");
410  SpeedButton80->Glyph->LoadFromResourceName(0, "gl80");
411  SpeedButton81->Glyph->LoadFromResourceName(0, "gl81");
412  SpeedButton82->Glyph->LoadFromResourceName(0, "gl82");
413  SpeedButton83->Glyph->LoadFromResourceName(0, "gl83");
414  SpeedButton84->Glyph->LoadFromResourceName(0, "gl84");
415  SpeedButton85->Glyph->LoadFromResourceName(0, "gl85");
416  SpeedButton86->Glyph->LoadFromResourceName(0, "gl86");
417  SpeedButton87->Glyph->LoadFromResourceName(0, "gl87");
418  SpeedButton88->Glyph->LoadFromResourceName(0, "gl88set");
419  SpeedButton89->Glyph->LoadFromResourceName(0, "gl89set");
420  SpeedButton90->Glyph->LoadFromResourceName(0, "gl90set");
421  SpeedButton91->Glyph->LoadFromResourceName(0, "gl91set");
422  SpeedButton92->Glyph->LoadFromResourceName(0, "gl92set");
423  SpeedButton93->Glyph->LoadFromResourceName(0, "gl93set");
424  SpeedButton94->Glyph->LoadFromResourceName(0, "gl94set");
425  SpeedButton95->Glyph->LoadFromResourceName(0, "gl95set");
426  SpeedButton96->Glyph->LoadFromResourceName(0, "ConcourseGlyph");
427  SpeedButton97->Glyph->LoadFromResourceName(0, "gl97");
428  SpeedButton98->Glyph->LoadFromResourceName(0, "gl98");
429  SpeedButton99->Glyph->LoadFromResourceName(0, "gl99");
430  SpeedButton100->Glyph->LoadFromResourceName(0, "gl100");
431  SpeedButton101->Glyph->LoadFromResourceName(0, "gl101");
432  SpeedButton102->Glyph->LoadFromResourceName(0, "gl102");
433  SpeedButton103->Glyph->LoadFromResourceName(0, "gl103");
434  SpeedButton104->Glyph->LoadFromResourceName(0, "gl104");
435  SpeedButton105->Glyph->LoadFromResourceName(0, "gl105");
436  SpeedButton106->Glyph->LoadFromResourceName(0, "gl106");
437  SpeedButton107->Glyph->LoadFromResourceName(0, "gl107");
438  SpeedButton108->Glyph->LoadFromResourceName(0, "gl108");
439  SpeedButton109->Glyph->LoadFromResourceName(0, "gl109");
440  SpeedButton110->Glyph->LoadFromResourceName(0, "gl110");
441  SpeedButton111->Glyph->LoadFromResourceName(0, "gl111");
442  SpeedButton112->Glyph->LoadFromResourceName(0, "gl112");
443  SpeedButton113->Glyph->LoadFromResourceName(0, "gl113");
444  SpeedButton114->Glyph->LoadFromResourceName(0, "gl114");
445  SpeedButton115->Glyph->LoadFromResourceName(0, "gl115");
446  SpeedButton116->Glyph->LoadFromResourceName(0, "gl116");
447  SpeedButton117->Glyph->LoadFromResourceName(0, "gl117");
448  SpeedButton118->Glyph->LoadFromResourceName(0, "gl118");
449  SpeedButton119->Glyph->LoadFromResourceName(0, "gl119");
450  SpeedButton120->Glyph->LoadFromResourceName(0, "gl120");
451  SpeedButton121->Glyph->LoadFromResourceName(0, "gl121");
452  SpeedButton122->Glyph->LoadFromResourceName(0, "gl122");
453  SpeedButton123->Glyph->LoadFromResourceName(0, "gl123");
454  SpeedButton124->Glyph->LoadFromResourceName(0, "gl124");
455  SpeedButton125->Glyph->LoadFromResourceName(0, "gl125");
456  SpeedButton126->Glyph->LoadFromResourceName(0, "gl126");
457  SpeedButton127->Glyph->LoadFromResourceName(0, "gl127");
458  SpeedButton128->Glyph->LoadFromResourceName(0, "gl128");
459  SpeedButton129->Glyph->LoadFromResourceName(0, "gl129");
460  SpeedButton130->Glyph->LoadFromResourceName(0, "gl130");
461  SpeedButton131->Glyph->LoadFromResourceName(0, "gl131");
462  SpeedButton132->Glyph->LoadFromResourceName(0, "gl132");
463  SpeedButton133->Glyph->LoadFromResourceName(0, "gl133");
464  SpeedButton134->Glyph->LoadFromResourceName(0, "gl134");
465  SpeedButton135->Glyph->LoadFromResourceName(0, "gl135");
466  SpeedButton136->Glyph->LoadFromResourceName(0, "gl136");
467  SpeedButton137->Glyph->LoadFromResourceName(0, "gl137");
468  SpeedButton138->Glyph->LoadFromResourceName(0, "gl138");
469  SpeedButton139->Glyph->LoadFromResourceName(0, "gl139");
470  SpeedButton140->Glyph->LoadFromResourceName(0, "gl140");
471  SpeedButton141->Glyph->LoadFromResourceName(0, "gl141");
472  SpeedButton142->Glyph->LoadFromResourceName(0, "gl142");
473  SpeedButton143->Glyph->LoadFromResourceName(0, "gl143");
474  SpeedButton145->Glyph->LoadFromResourceName(0, "gl145");
475  SpeedButton146->Glyph->LoadFromResourceName(0, "gl146");
476  // below not in RailGraphics
477  SpeedButton144->Glyph->LoadFromResourceName(0, "LCGlyph");
478 
479  AddPrefDirButton->Glyph->LoadFromResourceName(0, "AddPrefDir");
480  AddTextButton->Glyph->LoadFromResourceName(0, "AddText");
481  AddTrackButton->Glyph->LoadFromResourceName(0, "AddTrack");
482  AutoSigsButton->Glyph->LoadFromResourceName(0, "AutoSig");
483  CallingOnButton->Glyph->LoadFromResourceName(0, "CallingOn");
484  DeleteAllPrefDirButton->Glyph->LoadFromResourceName(0, "ClearAllPrefDir");
485  DeleteOnePrefDirButton->Glyph->LoadFromResourceName(0, "ClearOnePrefDir");
486  ExitOperationButton->Glyph->LoadFromResourceName(0, "Exit");
487  ExitPrefDirButton->Glyph->LoadFromResourceName(0, "Exit");
488  ExitTrackButton->Glyph->LoadFromResourceName(0, "Exit");
489  ExitTTModeButton->Glyph->LoadFromResourceName(0, "Exit");
490  FontButton->Glyph->LoadFromResourceName(0, "FontGraphic");
491  HomeButton->Glyph->LoadFromResourceName(0, "Home");
492  LocationNameButton->Glyph->LoadFromResourceName(0, "NameLocs");
493  MoveTextOrGraphicButton->Glyph->LoadFromResourceName(0, "MoveTextOrGraphic");
494  NewHomeButton->Glyph->LoadFromResourceName(0, "NewHome");
495  UnrestrictedButton->Glyph->LoadFromResourceName(0, "NonSig");
496  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
497  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
498  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
499  PresetAutoSigRoutesButton->Glyph->LoadFromResourceName(0, "PresetAutoSigRoutes");
500  RouteCancelButton->Glyph->LoadFromResourceName(0, "RouteCancel");
501  SaveRailwayPDPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // PrefDirPanel
502  SaveRailwayBaseModeButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // OperatingPanel
503  SaveRailwayTBPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // TrackBuildPanel
504  SaveSessionButton->Glyph->LoadFromResourceName(0, "SaveSession");
505  ScreenDownButton->Glyph->LoadFromResourceName(0, "BlackArrowDown");
506  ScreenGridButton->Glyph->LoadFromResourceName(0, "ScreenGrid");
507  ScreenLeftButton->Glyph->LoadFromResourceName(0, "BlackArrowLeft");
508  ScreenRightButton->Glyph->LoadFromResourceName(0, "BlackArrowRight");
509  ScreenUpButton->Glyph->LoadFromResourceName(0, "BlackArrowUp");
510  SetGapsButton->Glyph->LoadFromResourceName(0, "ConnectGaps");
511  SetLengthsButton->Glyph->LoadFromResourceName(0, "SetDists");
512  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
513  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect"); // new at version 0.6
514  SigPrefConsecButton->Glyph->LoadFromResourceName(0, "PrefTop");
515  SigPrefNonConsecButton->Glyph->LoadFromResourceName(0, "PrefBottom");
516  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
517  TrackOKButton->Glyph->LoadFromResourceName(0, "Validate");
518  TTClockAdjButton->Glyph->LoadFromResourceName(0, "TTClock");
519  UserGraphicButton->Glyph->LoadFromResourceName(0, "PictureImage");
520 
521  BufferAttentionImage->Picture->Bitmap->LoadFromResourceName(0, "BufferWarning");
522  CallOnImage->Picture->Bitmap->LoadFromResourceName(0, "CallingOn");
523  CrashImage->Picture->Bitmap->LoadFromResourceName(0, "CrashWarning");
524  DerailImage->Picture->Bitmap->LoadFromResourceName(0, "DerailWarning");
525  SignalStopImage->Picture->Bitmap->LoadFromResourceName(0, "SignalStopWarning");
526  SPADImage->Picture->Bitmap->LoadFromResourceName(0, "SPADWarning");
527  TrainFailedImage->Picture->Bitmap->LoadFromResourceName(0, "TrainFailedWarning"); // new at v2.4.0
528 
529  DistanceKey->Picture->Bitmap->LoadFromResourceName(0, "DistanceKey");
530  PrefDirKey->Picture->Bitmap->LoadFromResourceName(0, "PrefDirKey");
531 
532  TrackLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackLinkedGraphic");
533  TrackNotLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackNotLinkedGraphic");
534  GapsNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsNotSetGraphic");
535  GapsSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsSetGraphic");
536  LocationNamesNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesNotSetGraphic");
537  LocationNamesSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesSetGraphic");
538 
539 /* Don't need this - load icon directly into both Interface form & Application (via Project - Options - Application - Load Icon)
540  RailwayIcon = new TPicture;
541  RailwayIcon->Icon->LoadFromResourceName(0, "Icon1.ico");
542  Icon = RailwayIcon->Icon;
543  Application->Icon = RailwayIcon->Icon;
544 */
545 
546  AnsiString NL = '\n';
547  const AnsiString TTLabelStr1 = "Start new train" + NL + "Start new service from a split" + NL + "Start new service from another service" + NL +
548  "Start new non-repeating shuttle finish service" + NL + "Start new shuttle train at a timetabled stop" + NL +
549  "Start new shuttle service from a feeder";
550 
551  const AnsiString TTLabelStr2 = "Pass" + NL + "Be joined by another train" + NL + "Front split" + NL + "Rear split" + NL + "Change direction of train";
552 
553  const AnsiString TTLabelStr3 = "Finish && form a new service" + NL + "Finish && join another train" + NL + "Finish && exit railway" + NL +
554  "Finish && repeat shuttle, finally remain here" + NL + "Finish && repeat shuttle, finally form a finishing service" + NL +
555  "Finish non-repeating shuttle feeder service" + NL + "Finish && remain here";
556 
557  const AnsiString TTLabelStr4 = "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL +
558  "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + " " + NL + "R";
559 
560  const AnsiString TTLabelStr5 = "HH:MM ';' Location" + NL + "HH:MM ';' HH:MM ';' Location";
561 
562  const AnsiString TTLabelStr6 = "+ rear element ID - space - front element ID [+ optional ';S']" + NL + "+ ref. of the train that splits" + NL +
563  "+ other service ref." + NL + "+ shuttle service ref." + NL + "+ rear element ID - space - front element ID ';' linked shuttle ref." + NL +
564  "+ linked shuttle service ref. ';' feeder service ref." + NL + "+ location" + NL + "+ joining train ref." + NL + "+ new service ref." + NL +
565  "+ new service ref." + NL + " " + NL + "+ new service ref." + NL + "+ ref. of train to join" + NL +
566  "+ list of valid exit element IDs (at least 1) separated by spaces" + NL + "+ linked shuttle service ref.";
567 
568  const AnsiString TTLabelStr7 = "Arrival OR departure time (program will determine which from the context) + location." + NL +
569  "Arrival time, departure time (with no events between) + location";
570 
571  const AnsiString TTLabelStr9 = "Timetable entries" + NL + "(service references etc.)";
572  const AnsiString TTLabelStr11 = "Timetable" + NL + "start time";
573 
574  const AnsiString TTLabelStr12 = "NB: WITHIN SERVICES commas must" + NL + "not be used (have special meanings)," + NL +
575  "and semicolons may only be used to" + NL + "separate service components.";
576 
577  const AnsiString TTLabelStr13 = "+ linked shuttle service ref. ';' finishing service ref." + NL + "+ linked shuttle service ref.";
578 
579  const AnsiString TTLabelStr15 = "Repeat the service + ';' minutes between repeats ';' digit increment ';' number of repeats (last line of service)";
580 
581  TTLabel1->Caption = TTLabelStr1;
582  TTLabel2->Caption = TTLabelStr2;
583  TTLabel3->Caption = TTLabelStr3;
584  TTLabel4->Caption = TTLabelStr4;
585  TTLabel5->Caption = TTLabelStr5;
586  TTLabel6->Caption = TTLabelStr6;
587  TTLabel7->Caption = TTLabelStr7;
588  TTLabel9->Caption = TTLabelStr9;
589  TTLabel11->Caption = TTLabelStr11;
590  TTLabel12->Caption = TTLabelStr12;
591  TTLabel13->Caption = TTLabelStr13;
592  TTLabel15->Caption = TTLabelStr15;
593 
594  SelectBitmap->TransparentColor = Utilities->clTransparent;
595  RailGraphics->ChangeAllTransparentColours(Utilities->clTransparent, clB5G5R5); // original colour is as loaded at this stage - white
597 
598  TextBox->Color = clB3G3R3;
599  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
600  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
601 
602  if((Screen->Width < 1024) || (Screen->Height < 768))
603  {
604  ShowMessage("Please note that this program works best with a screen resolution of at least 1024 x 768. Please change if possible");
605  }
606 
607  SkipFormResizeEvent = true; // added at v2.1.0
608  MasterClock->Enabled = true;
609  Visible = true; // make Interface form visible (set to false at design time) autocalls FormResize so it is skipped
610  WindowState = wsMaximized; // need this for full screen at start autocalls FormResize so it is skipped
611  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30; // new v2.4.0 30 is to place it above the positional panel
612  // has to come after Visible = true or doesn't show
613  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
614  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
615  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
616  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
617  AllSetUpFlag = true;
618  MissedTicks = 0;
619  TotalTicks = 0;
621  SetLevel1Mode(131); // to reset background colour mode menu choices
622  Screen->Cursor = TCursor(-2); // Arrow
623  SkipFormResizeEvent = false; // added at v2.1.0
624  SelectedGraphicFileName = ""; // only set to null here so always has a value after use LoadUserGraphic
625 
626  FloatingPanel->Color = TColor(0xF0FFFF); // new v2.2.0, corrects floating panel background colour in Windows 10
627  PerformancePanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
628  OperatorActionPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
629  DevelopmentPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
630  TTStartTimeBox->Color = TColor(0x99FFFF); // cream
631  HighlightPanel->Color = TColor(0x33CCFF);
633  MTBFEditBox->Visible = false; // new at v2.4.0
634  MTBFLabel->Visible = false;
638  TTStartTimePtr = 0;
639  TTFirstServicePtr = 0;
640  TTLastServicePtr = 0;
641  Track->OverrideAndHideSignalBridgeMessage = false; //added at v2.5.1 to allow facing signals before bridges - with a warning
642  ConflictPanel->Visible = false;
643  TTClockAdjustWarningPanel->Visible = false;
644  TTClockAdjustWarningHide = false;
645  LastNonCtrlOrShiftKeyDown = -1; //set to no key
646 
647  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
648 
649  // below added at v2.4.0 so able to load session files with the correct decimal point
650  Utilities->DecimalPoint = '.'; // default case is full stop
651  char *LocalNumericInformation = setlocale(LC_NUMERIC, ""); // need this to set lconv to the environment's numeric format
653  if(LocalNumericInformation == "") // call failed, don't change decimal point in Utilities.cpp
654  {
655  Utilities->SetLocaleResultOK = false;
656  }
657  struct lconv Locale; // store this structure in memory (accessed via locale.h in Utilities.h)
658  struct lconv *conv = &Locale;
659  // read the locality conversion structure
660  conv = localeconv(); // this is what updates the structure
661  Utilities->DecimalPoint = conv->decimal_point[0];
662  }
663 
664  catch(const EFOpenError &e)
665  {
666  TMsgDlgButtons But;
667  But << mbOK;
668  MessageDlg(e.Message + " - program must terminate", mtError, But, 0);
669  Application->Terminate();
670  }
671 
672  catch(const Exception &e)
673  {
674  TMsgDlgButtons But;
675  But << mbOK;
676  AnsiString Message = "A fatal error occurred during the program setup process, the program must terminate. Message = " + e.Message;
677  MessageDlg(Message, mtError, But, 0); // this message given first in case can't create the error log
678  ErrorLog(115, e.Message);
679  Application->Terminate();
680  }
681 }
682 
683 // ---------------------------------------------------------------------------
684 
686 { // destructor
687  try
688  {
689  //rewrite ConfigFile with signal handedness, background colour & InitialDir values (may be same but no matter)
690  AnsiString ColourStr = "", SignalStr = "";
691  remove((CurDir + "\\Config.txt").c_str());
692  std::ofstream ConfigFile((CurDir + "\\Config.txt").c_str());
693  ColourStr = "black";
694  SignalStr = "left";
695  if(Utilities->clTransparent == TColor(0xFFFFFF))
696  {
697  ColourStr = "white";
698  }
699  else if(Utilities->clTransparent == TColor(0x330000))
700  {
701  ColourStr = "blue";
702  }
704  {
705  SignalStr = "right";
706  }
707 
708  ConfigFile << AnsiString("Signals=") << SignalStr << '\n';
709  ConfigFile << AnsiString("BgndCol=") << ColourStr << '\n';
710  ConfigFile << AnsiString("RLYLocn=") << AnsiString(LoadRailwayDialog->InitialDir) << '\n';
711  ConfigFile << AnsiString("TTBLocn=") << AnsiString(TimetableDialog->InitialDir) << '\n';
712  ConfigFile << AnsiString("SSNLocn=") << AnsiString(LoadSessionDialog->InitialDir) << '\n';
713  ConfigFile.close();
714 
715  SkipFormResizeEvent = true; // added at v2.1.0
716  delete NonSigRouteStartMarker;
717  delete SigRouteStartMarker;
718  delete AutoRouteStartMarker;
719  delete PointFlash;
720  delete SelectBitmap;
721  delete TrainController;
722  delete EveryPrefDir;
723  delete ConstructRoute;
724  delete ConstructPrefDir;
725  delete AllRoutes;
726  delete Track;
727  delete TextHandler;
728  delete HiddenDisplay;
729  delete HiddenScreen;
730  delete Display;
731  delete RailGraphics;
732  delete Utilities;
733  DeleteFile(TempTTFileName); //added after v2.4.3 to prevent temporary files building up
734  }
735  catch(const Exception &e)
736  {
737  ErrorLog(116, e.Message);
738  }
739 }
741 
742 // ---------------------------------------------------------------------------
743 
744 void __fastcall TInterface::FormCreate(TObject *Sender)
745 { // these functions have to be defined here to take effect when application activated & deactivated
746  try
747  {
748  Application->OnDeactivate = AppDeactivate;
749  Application->OnActivate = AppActivate;
750  }
751  catch(const Exception &e)
752  {
753  ErrorLog(117, e.Message);
754  }
755 }
756 
757 // ---------------------------------------------------------------------------
758 
759 void __fastcall TInterface::AppDeactivate(TObject *Sender)
760 { // pause operation if operating & stop the master clock
761  try
762  {
764  {
765  if(Track->RouteFlashFlag) // in case route building - cancels the route, freezes otherwise - reported
766  { // by Matt Blades 30/06/11
770  Screen->Cursor = TCursor(-2); // Arrow
771  Track->RouteFlashFlag = false;
772  ClearandRebuildRailway(48); // to get rid of displayed route
773  }
774  if(Track->PointFlashFlag)
775  // added at v1.3.1 to prevent lockup for flashing points when deactivates. Notified by Ian Walker in his email of 25/03/13.
776  {
778  Track->PointFlashFlag = false;
780  Screen->Cursor = TCursor(-2); // Arrow
781  }
784  }
785  MasterClock->Enabled = false;
786  }
787  catch(const Exception &e)
788  {
789  ErrorLog(118, e.Message);
790  }
791 }
792 
793 // ---------------------------------------------------------------------------
794 
795 void __fastcall TInterface::AppActivate(TObject *Sender)
796 { // restart the master clock providing Interface constructor has run
797  try
798  {
799  if(AllSetUpFlag)
800  {
801  MasterClock->Enabled = true;
802  }
803  }
804  catch(const Exception &e)
805  {
806  ErrorLog(119, e.Message);
807  }
808 }
809 
810 // ---------------------------------------------------------------------------
811 
812 UnicodeString TInterface::GetVersion()
813 {
814  DWORD VersionHandle;
815  DWORD VersionSize;
816  LPBYTE pBuffer;
817  UnicodeString strVersion = L"N/A";
818 
819  VersionSize = GetFileVersionInfoSizeW(Application->ExeName.c_str(), &VersionHandle);
820  if(VersionSize)
821  {
822  pBuffer = new BYTE[VersionSize];
823 
824  if(GetFileVersionInfoW(Application->ExeName.c_str(), VersionHandle, VersionSize, pBuffer))
825  {
826  VS_FIXEDFILEINFO *fi;
827  UINT buflen;
828 
829  // uncomment strVersion and HIWORD alternates below when future CI implemented: sas@2.1.0
830  if(VerQueryValueW(pBuffer, L"\\", (void**)&fi, &buflen))
831  {
832  // strVersion.sprintf(L"%d.%d.%d (Build %d)",
833  strVersion.sprintf(L"%d.%d.%d", HIWORD(fi->dwFileVersionMS), LOWORD(fi->dwFileVersionMS), HIWORD(fi->dwFileVersionLS)
834  // HIWORD(fi->dwFileVersionLS), LOWORD(fi->dwFileVersionLS)
835  );
836  }
837  }
838 
839  delete[]pBuffer;
840  }
841 
842  return L" v" + strVersion;
843 }
844 
845 // ---------------------------------------------------------------------------
846 // Track Build Interface
847 // ---------------------------------------------------------------------------
848 void __fastcall TInterface::BuildTrackMenuItemClick(TObject *Sender) // Mode Menu Item
849 {
850  try
851  {
852  TrainController->LogEvent("BuildTrackMenuItemClick");
853  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildTrackMenuItemClick");
855  SetLevel1Mode(0);
856  Utilities->CallLogPop(1159);
857  }
858  catch(const Exception &e)
859  {
860  ErrorLog(120, e.Message);
861  }
862 }
863 // ---------------------------------------------------------------------------
864 
865 void __fastcall TInterface::AddTrackButtonClick(TObject *Sender)
866 {
867  try
868  {
869  TrainController->LogEvent("AddTrackButtonClick");
870  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTrackButtonClick");
872  SetLevel1Mode(38);
875  Utilities->CallLogPop(1162);
876  }
877  catch(const Exception &e)
878  {
879  ErrorLog(121, e.Message);
880  }
881 }
882 
883 // ---------------------------------------------------------------------------
884 void __fastcall TInterface::SpeedButtonClick(TObject *Sender)
885 {
886  try
887  {
888  TrainController->LogEvent("SpeedButtonClick");
889  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedButtonClick");
890  ReselectMenuItem->Enabled = false;
891  if(((TSpeedButton*)Sender)->Down)
892  {
893  CurrentSpeedButton = (TSpeedButton*)Sender;
894 // TrainController->LogEvent("SpeedButtonClick, " + CurrentSpeedButton->Tag); //v 1.3.1 - using non-AnsiString CurrentSpeedButton->Tag sends (for an unknown reason) a completely wrong string to LogEvent, usually "...(behind this message)"
895  TrainController->LogEvent("SpeedButtonClick, " + AnsiString(CurrentSpeedButton->Tag)); // new version //use for v1.3.2
896  if((Level2TrackMode == TrackSelecting) && (CurrentSpeedButton->Tag != 144)) //new addition at v2.6.0 to fill selected area with the element corresponding to CurrentSpeedButton
897  { //144 = level crossing & these not permitted
898  if((SelectRect.left != SelectRect.right) && (SelectRect.top != SelectRect.bottom) && SelectionValid)
899  {
900  Screen->Cursor = TCursor(-11); // Hourglass;
901  InfoPanel->Caption = "SELECTING: Filling area with chosen element";
902  bool FillSelectionFlag = false;
904  {
905  UnicodeString MessageStr = "Click 'Yes' to fill the area with the chosen element or 'No' to abort.\n"
906  "Existing elements won't be overwritten although track can\n"
907  "have platforms and non-station named location elements added.\n\nThis message will not be shown again.";
908  int button = Application->MessageBox(MessageStr.c_str(), L"", MB_YESNO);
909  if(button == IDYES)
910  {
911  FillSelectionFlag = true;
912  }
913  }
914  if(FillSelectionFlag || FillSelectionMessageSentFlag)
915  {
916  bool TrackLinkingRequiredFlag = true;
917  for(int HLoc = SelectRect.left; HLoc < SelectRect.right; HLoc++)
918  {
919  for(int VLoc = SelectRect.top; VLoc < SelectRect.bottom; VLoc++)
920  {
921  if((HLoc != SelectRect.right) || (VLoc != SelectRect.bottom))
922  {
923  Track->PlotAndAddTrackElement(3, CurrentSpeedButton->Tag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, false); //false for internal checks
924  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
925  }
926  else
927  {
928  Track->PlotAndAddTrackElement(4, CurrentSpeedButton->Tag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, true); //internal checks true for last plot
929  }
930  }
931  }
932  }
933  Track->SetTrackFinished(false);
934  ClearandRebuildRailway(80); // to remove selection outline
935  SelectionValid = false;
936  Track->CopyFlag = false;
938  ResetSelectRect();
939  SetLevel1Mode(139);
941  SetLevel2TrackMode(66);
943  Screen->Cursor = TCursor(-2); // Arrow
944  ReselectMenuItem->Enabled = true; //allow when filling areas
945  }
946  }
947  }
948  else
949  {
950  CurrentSpeedButton = 0;
951  }
952  Utilities->CallLogPop(1163);
953  }
954  catch(const Exception &e)
955  {
956  ErrorLog(122, e.Message);
957  }
958 }
959 
960 // ---------------------------------------------------------------------------
961 void __fastcall TInterface::TrackOKButtonClick(TObject *Sender)
962 {
963  try
964  {
965  TrainController->LogEvent("TrackOKButtonClick");
966  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackOKButtonClick");
967  SelectionValid = false;
969  bool LocError;
970  int HLoc, VLoc;
971  // erase any corrupted PrefDirs then rebuild track & PrefDir vectors
972 // EveryPrefDir->EraseCorruptedElementsAfterTrackBuild(); not needed after dispensed with blank track elements for erased elements
973  if(!(Track->TryToConnectTrack(0, LocError, HLoc, VLoc, true))) // true for give messages
974  // if successful repositions TrackVector & builds TrackMap
975  {
976  if(LocError) // links not complete or other error - show offending element
977  {
978  while((Display->DisplayOffsetH - HLoc) > 0)
979  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
980  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
982  while((Display->DisplayOffsetV - VLoc) > 0)
983  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
984  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
987  Display->InvertElement(0, HLoc * 16, VLoc * 16);
988  ShowMessage("Incomplete track or other error - see inverted element (may be behind this message)");
989  ClearandRebuildRailway(1); // to clear inversion
991  SetLevel1Mode(39);
992  Level2TrackMode = AddTrack; // go to add track regardless of where started from
994  Utilities->CallLogPop(0);
995  return;
996  }
997  else
998  { // reach here if there are no track elements
999  ShowMessage("Unable to set any track links");
1001  SetLevel1Mode(40);
1003  SetLevel2TrackMode(4); // go to add track regardless of where started from
1004  Utilities->CallLogPop(1);
1005  return;
1006  }
1007  }
1008  else
1009  {
1010  // success ('TrackFinished' set in TryToConnectTrack)
1011  EveryPrefDir->RebuildPrefDirVector(0); // from TrackMap
1012  ShowMessage("Successful Completion");
1013  }
1014 // success if reach here ('TrackFinished' set in TryToConnectTrack)
1015  if(Level2TrackMode == AddTrack)
1016  {
1018  SetLevel1Mode(41);
1019  SetLevel2TrackMode(5);
1020  }
1021  else
1022  {
1024  SetLevel1Mode(36); // back to TrackMode if not in AddTrack mode
1025  }
1026  Utilities->CallLogPop(2);
1027  }
1028  catch(const Exception &e)
1029  {
1030  ErrorLog(3, e.Message);
1031  }
1032 }
1033 
1034 // ---------------------------------------------------------------------------
1035 void __fastcall TInterface::SetGapsButtonClick(TObject *Sender)
1036 {
1037  try
1038  {
1039  TrainController->LogEvent("SetGapsButtonClick");
1040  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetGapsButtonClick");
1041  SelectionValid = false;
1042  ReselectMenuItem->Enabled = false;
1044  SetLevel1Mode(42);
1046  SetLevel2TrackMode(6);
1047  Utilities->CallLogPop(1164);
1048  }
1049  catch(const Exception &e)
1050  {
1051  ErrorLog(123, e.Message);
1052  }
1053 }
1054 
1055 // ---------------------------------------------------------------------------
1056 void __fastcall TInterface::AddTextButtonClick(TObject *Sender)
1057 {
1058  try
1059  {
1060  TrainController->LogEvent("AddTextButtonClick");
1061  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTextButtonClick");
1063  SetLevel1Mode(43);
1065  SetLevel2TrackMode(7);
1066  Utilities->CallLogPop(1165);
1067  }
1068  catch(const Exception &e)
1069  {
1070  ErrorLog(124, e.Message);
1071  }
1072 }
1073 
1074 // ---------------------------------------------------------------------------
1075 void __fastcall TInterface::MoveTextOrGraphicButtonClick(TObject *Sender)
1076 {
1077  try
1078  {
1079  TrainController->LogEvent("MoveTextOrGraphicButtonClick");
1080  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTextOrGraphicButtonClick");
1082  SetLevel1Mode(44);
1084  SetLevel2TrackMode(8);
1085  Utilities->CallLogPop(1166);
1086  }
1087  catch(const Exception &e)
1088  {
1089  ErrorLog(125, e.Message);
1090  }
1091 }
1092 
1093 // ---------------------------------------------------------------------------
1094 void __fastcall TInterface::TextBoxKeyPress(TObject *Sender, char &Key)
1095 {
1096  try
1097  {
1098  TrainController->LogEvent("TextBoxKeyPress," + AnsiString(Key));
1099  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextBoxKeyPress," + AnsiString(Key));
1100  if(Key == '\x0D') // CR
1101  {
1102  if(TextBox->Text != "") // if blank then don't save
1103  {
1104  if(Display->GetFont()->Color == clB5G5R5) // white
1105  {
1106  TFont *TempFont = new TFont;
1107  TempFont->Assign(Display->GetFont());
1108  TempFont->Color = clB0G0R0; // change to black for vector & saving
1109  Display->SetFont(TempFont);
1110  delete TempFont;
1111  }
1112  TFont *DisplayFont = Display->GetFont();
1113  TTextItem TempText = TTextItem(Text_X, Text_Y, TextBox->Text, DisplayFont);
1114  TempText.Font = DisplayFont; // may have been changed in above constructor when returned as reference
1116  }
1117  EditMenu->Enabled = true;
1118  TextBox->Visible = false;
1119  SetLevel2TrackMode(56); // to enable 'move text' if first text item added
1120  }
1121  else if(Key == '\x1B') // escape
1122  {
1123  TextBox->Visible = false;
1124  }
1125  Utilities->CallLogPop(3);
1126  }
1127  catch(const Exception &e)
1128  {
1129  ErrorLog(4, e.Message);
1130  }
1131 }
1132 
1133 // ---------------------------------------------------------------------------
1134 void __fastcall TInterface::LocationNameButtonClick(TObject *Sender)
1135 {
1136  try
1137  {
1138  TrainController->LogEvent("LocationNameButtonClick");
1139  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameButtonClick");
1141  SetLevel1Mode(45);
1143  SetLevel2TrackMode(9);
1144  Utilities->CallLogPop(1167);
1145  }
1146  catch(const Exception &e)
1147  {
1148  ErrorLog(126, e.Message);
1149  }
1150 }
1151 
1152 // ---------------------------------------------------------------------------
1153 void __fastcall TInterface::LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
1154 {
1155  try
1156  {
1157  TrainController->LogEvent("LocationNameKeyUp," + AnsiString(Key));
1158  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameKeyUp," + AnsiString(Key));
1159  if(Track->LNPendingList.empty())
1160  {
1161  ShowMessage("Error, location name being entered without an entry in LNPendingList");
1163  SetLevel1Mode(46);
1165  SetLevel2TrackMode(10);
1166  Utilities->CallLogPop(4);
1167  return;
1168  }
1169  if(Key == '\x1B') // escape
1170  {
1171  Track->LNPendingList.clear(); // get rid of existing entry
1173  SetLevel1Mode(47);
1175  SetLevel2TrackMode(11);
1176  Utilities->CallLogPop(5);
1177  return;
1178  }
1179  if(Key == '\x0D')
1180  {
1181  Screen->Cursor = TCursor(-11); // Hourglass;
1183  AnsiString ExistingName;
1184  LocationNameTextBox->Text = LocationNameTextBox->Text.Trim(); //added at v2.6.1 to prevent added spaces because they skip the different location same name chack
1185  if(Track->LNPendingList.front() > -1)
1186  ExistingName = Track->InactiveTrackElementAt(27, Track->LNPendingList.front()).LocationName;
1187  else
1188  ExistingName = Track->TrackElementAt(425, -1 - (Track->LNPendingList.front())).LocationName;
1189  if(Track->LocationNameAllocated(1, LocationNameTextBox->Text) && (ExistingName != LocationNameTextBox->Text))
1190  { // name allocated to a different location
1191  UnicodeString MessageStr = UnicodeString("Another location named '") + LocationNameTextBox->Text +
1192  UnicodeString("' already exists. If you continue its name will be erased. Do you wish to continue?");
1193  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
1194  if(button == IDNO)
1195  {
1196  Track->LNPendingList.clear(); // get rid of existing entry
1197  Screen->Cursor = TCursor(-2); // Arrow
1199  SetLevel1Mode(48);
1201  SetLevel2TrackMode(12);
1202  Utilities->CallLogPop(6);
1203  return;
1204  }
1206  Track->EnterLocationName(1, LocationNameTextBox->Text, false);
1207  int HPos, VPos;
1208  bool UseExistingPosition = false;
1209  if(EraseLocationNameText(0, LocationNameTextBox->Text, HPos, VPos))
1210  {;
1211  } // condition not used
1212  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1213  // but, the location to be named may also have an existing name, in which case that needs to be erased
1214  // and the position re-used
1215  if(ExistingName != "")
1216  {
1217  if(EraseLocationNameText(3, ExistingName, HPos, VPos))
1218  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1219  }
1220  AddLocationNameText(0, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1221  Screen->Cursor = TCursor(-2); // Arrow
1223  SetLevel1Mode(49);
1225  SetLevel2TrackMode(13);
1226  Utilities->CallLogPop(7);
1227  return;
1228  }
1229  else if(Track->LocationNameAllocated(2, LocationNameTextBox->Text) && (ExistingName == LocationNameTextBox->Text))
1230  { // same name being entered again
1231  Track->LNPendingList.clear(); // get rid of existing entry as the location already has this name
1232  // but in case the name is not already in text vector erase it and re-add it
1233  // if it wasn't in the vector erasing it has no effect
1234  int HPos, VPos;
1235  bool UseExistingPosition = false;
1236  if(EraseLocationNameText(2, LocationNameTextBox->Text, HPos, VPos))
1237  UseExistingPosition = true;
1238  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1239  AddLocationNameText(2, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1240  Screen->Cursor = TCursor(-2); // Arrow
1242  SetLevel1Mode(50);
1244  SetLevel2TrackMode(14);
1245  Utilities->CallLogPop(8);
1246  return;
1247  }
1248  else
1249  { // either a new name for an unnamed location, or a different name for a named location
1250  // check validity of entry
1251  AnsiString LocStr = LocationNameTextBox->Text;
1252  LocStr = LocStr.Trim(); // strip leading & trailing spaces, and control characters
1253  LocationNameTextBox->Text = LocStr; // reset this as used below
1254 /* drop this, now covered by ...Trim() above
1255  //strip leading spaces
1256  while((LocStr != "") && (LocStr[1] == ' '))
1257  {
1258  LocStr = LocStr.SubString(2, LocStr.Length()-1);
1259  }
1260 */
1261  if((LocStr != "") && (LocStr[1] >= '0') && (LocStr[1] <= '9')) // can't begin with a number
1262  {
1263  Screen->Cursor = TCursor(-2); // Arrow
1264  ShowMessage("Location name can't begin with a number");
1266  SetLevel1Mode(51);
1268  SetLevel2TrackMode(15);
1269  Utilities->CallLogPop(776);
1270  return;
1271  }
1272  if(LocStr.Length() > 50)
1273  {
1274  Screen->Cursor = TCursor(-2); // Arrow
1275  ShowMessage("Location name too long, 50 characters maximum");
1277  SetLevel1Mode(122);
1279  SetLevel2TrackMode(55);
1280  Utilities->CallLogPop(1735);
1281  return;
1282  }
1283  for(int x = 1; x <= LocStr.Length(); x++)
1284  {
1285  char Ch = LocStr[x];
1286  if((Ch != ' ') && (Ch != '&') && (Ch != '(') && (Ch != ')') && (Ch != ':') && (Ch != 39) && (Ch != '.') && (Ch != '-') && (Ch != '+') &&
1287  (Ch != '/') && ((Ch < '0') || (Ch > '9')) && ((Ch < 'A') || (Ch > 'Z')) && ((Ch < 'a') || (Ch > 'z')))
1288  {
1289  Screen->Cursor = TCursor(-2); // Arrow
1290  ShowMessage(
1291  "Location name contains one or more invalid characters, must be alphanumeric, brackets, space, full stop, colon, inverted comma, '-', '+', '/' or '&&'");
1293  SetLevel1Mode(52);
1295  SetLevel2TrackMode(16);
1296  Utilities->CallLogPop(777);
1297  return;
1298  }
1299  }
1300  if(LocStr == "cdt") // this has Time:Command which could be confused with Time:Loc
1301  {
1302  Screen->Cursor = TCursor(-2); // Arrow
1303  ShowMessage("Location name cannot be 'cdt', this name would interfere with the timetable");
1305  SetLevel1Mode(53);
1307  SetLevel2TrackMode(17);
1308  Utilities->CallLogPop(778);
1309  return;
1310  }
1311  Track->EnterLocationName(2, LocStr, false);
1312  // need to check if the location already has a name, and if so erase it from the textvector
1313  int HPos, VPos;
1314  bool UseExistingPosition = false;
1315  if(ExistingName != "")
1316  {
1317  if(EraseLocationNameText(1, ExistingName, HPos, VPos))
1318  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1319  }
1320  AddLocationNameText(1, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1321  Screen->Cursor = TCursor(-2); // Arrow
1323  SetLevel1Mode(54);
1325  SetLevel2TrackMode(18);
1326  Utilities->CallLogPop(9);
1327  return;
1328  }
1329  }
1330  Screen->Cursor = TCursor(-2); // Arrow
1331  Utilities->CallLogPop(10);
1332  }
1333  catch(const Exception &e)
1334  {
1335  ErrorLog(5, e.Message);
1336  }
1337 }
1338 
1339 // ---------------------------------------------------------------------------
1340 void __fastcall TInterface::SetLengthsButtonClick(TObject *Sender)
1341 {
1342  try
1343  {
1344  TrainController->LogEvent("SetLengthsButtonClick");
1345  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetLengthsButtonClick");
1346  SelectLengthsFlag = false;
1347  ConstructPrefDir->ExternalClearPrefDirAnd4MultiMap(); // added for extended distances
1349  SetLevel1Mode(55);
1351  SetLevel2TrackMode(19);
1352  Utilities->CallLogPop(1168);
1353  }
1354  catch(const Exception &e)
1355  {
1356  ErrorLog(127, e.Message);
1357  }
1358 }
1359 
1360 // ---------------------------------------------------------------------------
1361 void __fastcall TInterface::LengthOKButtonClick(TObject *Sender)
1362 {
1363  try
1364  {
1365  TrainController->LogEvent("LengthOKButtonClick," + DistanceBox->Text + "," + SpeedLimitBox->Text);
1366  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthOKButtonClick");
1367  int Dist = 0, SpeedLimit = 0;
1368  AnsiString DistanceStr = DistanceBox->Text;
1369  if(SelectLengthsFlag && (DistanceStr == ""))
1370  DistanceStr = "No change";
1371  AnsiString SpeedStr = SpeedLimitBox->Text;
1372  if(SelectLengthsFlag && (SpeedStr == ""))
1373  SpeedStr = "No change";
1374  if(SelectLengthsFlag)
1375  {
1376  if(DistanceStr == "No change")
1377  Dist = -1; // i.e.don't change
1378  if(SpeedStr == "No change")
1379  SpeedLimit = -1; // i.e.don't change
1380  }
1381  else
1382  {
1383  if(DistanceStr == AnsiString(OverallDistance))
1384  Dist = -1; // i.e.don't change
1385  if((SpeedStr == "Mixed") || (SpeedStr == AnsiString(OverallSpeedLimit)))
1386  SpeedLimit = -1; // i.e.don't change
1387  }
1388  if(((Dist != -1) && (DistanceStr.Length() > 6)) || ((SpeedLimit != -1) && (SpeedStr.Length() > 6)))
1389  {
1390  ShowMessage("One or more entries too long");
1391  Utilities->CallLogPop(11);
1392  return;
1393  }
1394  if((DistanceStr == "") || (SpeedStr == ""))
1395  {
1396  ShowMessage("One or more entries blank");
1397  Utilities->CallLogPop(12);
1398  return;
1399  }
1400  if(SelectLengthsFlag && (Dist != -1))
1401  {
1402  for(int x = 1; x <= DistanceStr.Length(); x++)
1403  {
1404  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1405  {
1406  ShowMessage("Track length value must be a positive whole number, or blank for no change");
1407  Utilities->CallLogPop(1415);
1408  return;
1409  }
1410  }
1411  }
1412  if(!SelectLengthsFlag)
1413  {
1414  for(int x = 1; x <= DistanceStr.Length(); x++)
1415  {
1416  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1417  {
1418  ShowMessage("Distance must be a positive whole number");
1419  Utilities->CallLogPop(13);
1420  return;
1421  }
1422  }
1423  }
1424  if(SelectLengthsFlag && (SpeedLimit != -1))
1425  {
1426  for(int x = 1; x <= SpeedStr.Length(); x++)
1427  {
1428  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1429  {
1430  ShowMessage("Speed limit must be a positive whole number, or blank for no change");
1431  Utilities->CallLogPop(1416);
1432  return;
1433  }
1434  }
1435  }
1436  if(!SelectLengthsFlag && (SpeedStr != "Mixed"))
1437  {
1438  for(int x = 1; x <= SpeedStr.Length(); x++)
1439  {
1440  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1441  {
1442  ShowMessage("Speed limit must be a positive whole number, or 'Mixed'");
1443  Utilities->CallLogPop(14);
1444  return;
1445  }
1446  }
1447  }
1448  if(Dist != -1)
1449  Dist = DistanceStr.ToInt();
1450  if(SpeedLimit != -1)
1451  SpeedLimit = SpeedStr.ToInt();
1452 /* don't need this with new condition below
1453  if(SelectLengthsFlag && (Dist != -1) && (Dist < 20))
1454  {
1455  ShowMessage("Track length value must be a minimum of 20m, setting to 20m");
1456  Dist = 20;
1457  }
1458 */
1459  if(((Dist != -1) && (Dist < 20)) || ((SpeedLimit != -1) && (SpeedLimit < 10)) || ((SpeedLimit != -1) && (SpeedLimit > TTrain::MaximumSpeedLimit)))
1460  // new limiting values for v0.6 (used only to fail at either value 0); added TTrain::MaxSpeedLimit at v2.1.0
1461  {
1462  ShowMessage("Lengths must be 20m or more, and speeds must be between 10km/h and 400km/h"); // changed at v2.1.0 to limit max speed
1463  Utilities->CallLogPop(15);
1464  return;
1465  }
1466  DistanceBox->Text = "";
1467  SpeedLimitBox->Text = "";
1468  if(SelectLengthsFlag)
1469  {
1470  int LowSelectHLoc = SelectBitmapHLoc;
1471  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1472  int LowSelectVLoc = SelectBitmapVLoc;
1473  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1474  bool FoundFlag;
1475  bool NamedLocPresent = false;
1476  if((Dist != -1) && (Dist != DefaultTrackLength))
1477  {
1478  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1479  {
1480  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1481  {
1483  NamedLocPresent = true;
1484  }
1485  }
1486  }
1487  if(NamedLocPresent && (Dist < 50)) // changed in v2.4.0
1488  {
1489  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might depart too far from reality.");
1490  }
1491 
1492  if(NamedLocPresent && (Dist > 200)) // changed in v2.4.0
1493  {
1494  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might depart too far from reality.");
1495  }
1496 
1497  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1498  {
1499  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1500  {
1501  int VecPos = Track->GetVectorPositionFromTrackMap(34, x, y, FoundFlag);
1502  if(FoundFlag)
1503  {
1504  if(Dist > -1) // && !(Track->IsPlatformOrNamedNonStationLocationPresent(7, x, y)))
1505  {
1506  Track->TrackElementAt(692, VecPos).Length01 = Dist;
1507  if(Track->TrackElementAt(693, VecPos).Length23 != -1)
1508  {
1509  Track->TrackElementAt(694, VecPos).Length23 = Dist;
1510  }
1511  }
1512  if(SpeedLimit > -1)
1513  {
1514  Track->TrackElementAt(695, VecPos).SpeedLimit01 = SpeedLimit;
1515  if(Track->TrackElementAt(696, VecPos).SpeedLimit23 != -1)
1516  {
1517  Track->TrackElementAt(697, VecPos).SpeedLimit23 = SpeedLimit;
1518  }
1519  }
1520  }
1521  }
1522  }
1523  TrackLengthPanel->Visible = false;
1524  SelectLengthsFlag = false; // go back to normal distance setting mode
1525  }
1526  else
1527  {
1528  SetTrackLengths(1, Dist, SpeedLimit);
1529  }
1531  SetLevel1Mode(57);
1533  SetLevel2TrackMode(21);
1534  Utilities->CallLogPop(16);
1535  }
1536  catch(const Exception &e)
1537  {
1538  ErrorLog(6, e.Message);
1539  }
1540 }
1541 
1542 // ---------------------------------------------------------------------------
1543 void __fastcall TInterface::LengthCancelButtonClick(TObject *Sender)
1544 {
1545  try
1546  {
1547  TrainController->LogEvent("LengthCancelButtonClick");
1548  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthCancelButtonClick");
1549  DistanceBox->Text = "";
1550  SpeedLimitBox->Text = "";
1551  TrackLengthPanel->Visible = false;
1552  SelectLengthsFlag = false; // go back to normal distance setting mode
1554  SetLevel1Mode(59);
1556  SetLevel2TrackMode(23);
1557  Utilities->CallLogPop(1169);
1558  }
1559  catch(const Exception &e)
1560  {
1561  ErrorLog(128, e.Message);
1562  }
1563 }
1564 
1565 // ---------------------------------------------------------------------------
1566 void __fastcall TInterface::ResetDefaultLengthButtonClick(TObject *Sender)
1567 {
1568  try
1569  {
1570  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ResetDefaultLengthButtonClick");
1571  TMsgDlgButtons Buttons;
1572  Buttons << mbYes << mbNo;
1573  if(MessageDlg("This will reset the selected elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1574  {
1575  // leave all as was before
1576  Utilities->CallLogPop(17);
1577  return;
1578  }
1579  else
1580  {
1581  TrainController->LogEvent("Accepted ResetDefaultLengthButtonClick");
1582  DistanceBox->Text = "";
1583  SpeedLimitBox->Text = "";
1584  if(SelectLengthsFlag)
1585  {
1586  int LowSelectHLoc = SelectBitmapHLoc;
1587  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1588  int LowSelectVLoc = SelectBitmapVLoc;
1589  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1590  bool FoundFlag;
1591  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1592  {
1593  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1594  {
1595  int VecPos = Track->GetVectorPositionFromTrackMap(35, x, y, FoundFlag);
1596  if(FoundFlag)
1597  {
1599  if(Track->TrackElementAt(699, VecPos).Length23 != -1)
1600  {
1602  }
1604  if(Track->TrackElementAt(702, VecPos).SpeedLimit23 != -1)
1605  {
1607  }
1608  }
1609  }
1610  }
1611  TrackLengthPanel->Visible = false;
1612 // ClearandRebuildRailway(47); don't need this
1613  SelectLengthsFlag = false; // go back to normal distance setting mode
1614  }
1615  else
1616  {
1617  TrackLengthPanel->Visible = false;
1618  bool FoundFlag;
1619  if(ConstructPrefDir->PrefDirSize() == 0)
1620  {
1621  Utilities->CallLogPop(1120);
1622  return;
1623  }
1624  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
1625  {
1626  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(169, x);
1627  TTrackElement & TrackElement = Track->TrackElementAt(37, Track->GetVectorPositionFromTrackMap(40, PrefDirElement.HLoc, PrefDirElement.VLoc,
1628  FoundFlag));
1629  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover) || (TrackElement.TrackType == Bridge))
1630  // only set the relevant track to default length & speed limit
1631  {
1632  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be one of each for points
1633  {
1634  TrackElement.Length01 = DefaultTrackLength;
1635  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1636  }
1637  else
1638  {
1639  TrackElement.Length23 = DefaultTrackLength;
1640  TrackElement.SpeedLimit23 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1641  }
1642  }
1643  else // any other 1 track element, including platforms being present
1644  {
1645  if((PrefDirElement.GetELinkPos() > 1) && (PrefDirElement.GetXLinkPos() > 1))
1646  {
1647  throw Exception("Error, XLinkPos > 1 in SetOneDefaultTrackLength at " + AnsiString(TrackElement.HLoc) + " & " +
1648  AnsiString(TrackElement.VLoc));
1649  }
1650  TrackElement.Length01 = DefaultTrackLength;
1651  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1652  TrackElement.Length23 = -1;
1653  TrackElement.SpeedLimit23 = -1;
1654  }
1655  }
1656  }
1658  SetLevel1Mode(61);
1660  SetLevel2TrackMode(25);
1661  }
1662  Utilities->CallLogPop(18);
1663  }
1664  catch(const Exception &e)
1665  {
1666  ErrorLog(7, e.Message);
1667  }
1668 }
1669 
1670 // ---------------------------------------------------------------------------
1671 void __fastcall TInterface::RestoreAllDefaultLengthsButtonClick(TObject *Sender)
1672 {
1673  try
1674  {
1675  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreAllDefaultLengthsButtonClick");
1676  TMsgDlgButtons Buttons;
1677  Buttons << mbYes << mbNo;
1678  if(MessageDlg("This will reset ALL track elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1679  {
1680  // leave all as was before
1681  Utilities->CallLogPop(19);
1682  return;
1683  }
1684  else
1685  {
1687  }
1688  TrainController->LogEvent("Accepted RestoreAllDefaultLengthsButtonClick");
1689  DistanceBox->Text = "";
1690  SpeedLimitBox->Text = "";
1691  TrackLengthPanel->Visible = false;
1692  SelectLengthsFlag = false; // go back to normal distance setting mode
1694  SetLevel1Mode(63);
1696  SetLevel2TrackMode(27);
1697  Utilities->CallLogPop(20);
1698  }
1699  catch(const Exception &e)
1700  {
1701  ErrorLog(8, e.Message);
1702  }
1703 }
1704 
1705 // ---------------------------------------------------------------------------
1706 void __fastcall TInterface::ExitTrackButtonClick(TObject *Sender)
1707 {
1708  try
1709  {
1710  TrainController->LogEvent("ExitTrackButtonClick");
1711  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTrackButtonClick");
1712  if(Level2TrackMode == CutMoving)
1713  {
1714  Level2TrackMode = Pasting; // to paste the selection
1715  SetLevel2TrackMode(53);
1716  }
1717  DevelopmentPanel->Visible = false; // development use only
1718  ScreenGridFlag = false;
1719  SelectionValid = false;
1720  Track->SelectGraphicVector.clear();
1721  // delete all unwanted TPictures in UserGraphicMap
1722  if(!Track->UserGraphicMap.empty()) // if empty skip it
1723  {
1724  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1725  do
1726  {
1727  bool GraphicFoundInVector = false;
1728  for(TTrack::TUserGraphicVector::iterator UGVIt = Track->UserGraphicVector.begin(); UGVIt < Track->UserGraphicVector.end(); UGVIt++)
1729  {
1730  if(UGMIt->first == UGVIt->FileName)
1731  {
1732  GraphicFoundInVector = true;
1733  break;
1734  }
1735  }
1736  if(!GraphicFoundInVector)
1737  {
1738  delete UGMIt->second;
1739  Track->UserGraphicMap.erase(UGMIt);
1740  UGMIt = Track->UserGraphicMap.begin(); // reset the iterator because erasing an element it points to invalidates it & if use it after then
1741  // behaviour is undefined, the iteration will end eventually because the map has got shorter after an erase
1742  }
1743  else
1744  {
1745  UGMIt++;
1746  }
1747  }
1748  while(UGMIt != Track->UserGraphicMap.end());
1749  }
1750  Level1Mode = BaseMode;
1751  SetLevel1Mode(2);
1752  Utilities->CallLogPop(1170);
1753  }
1754  catch(const Exception &e)
1755  {
1756  ErrorLog(129, e.Message);
1757  }
1758 }
1759 
1760 // ---------------------------------------------------------------------------
1761 void __fastcall TInterface::TextOrUserGraphicGridButtonClick(TObject *Sender)
1762 {
1763  try
1764  {
1765  TrainController->LogEvent("TextOrUserGraphicGridButtonClick," + AnsiString(TextOrUserGraphicGridVal));
1766  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextOrUserGraphicGridButtonClick");
1767  if(TextOrUserGraphicGridVal == 1)
1768  {
1770  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision2");
1771  }
1772  else if(TextOrUserGraphicGridVal == 2)
1773  {
1775  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision4");
1776  }
1777  else if(TextOrUserGraphicGridVal == 4)
1778  {
1780  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision8");
1781  }
1782  else if(TextOrUserGraphicGridVal == 8)
1783  {
1785  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision16");
1786  }
1787  else
1788  {
1790  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
1791  }
1792  Utilities->CallLogPop(1171);
1793  }
1794  catch(const Exception &e)
1795  {
1796  ErrorLog(130, e.Message);
1797  }
1798 }
1799 
1800 // ---------------------------------------------------------------------------
1801 void __fastcall TInterface::SigAspectButtonClick(TObject *Sender)
1802 {
1803  try
1804  {
1805  TrainController->LogEvent("SigAspectButtonClick," + AnsiString(Track->SignalAspectBuildMode));
1806  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigAspectButtonClick");
1808  {
1810  SigAspectButton->Glyph->LoadFromResourceName(0, "ThreeAspect");
1811  }
1813  {
1815  SigAspectButton->Glyph->LoadFromResourceName(0, "TwoAspect");
1816  }
1818  {
1820  SigAspectButton->Glyph->LoadFromResourceName(0, "GroundSig");
1821 // set all signal glyphs to ground signals
1823  }
1824  else
1825  {
1827  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
1828 // set all signal glyphs to normal signals
1830  }
1831  Utilities->CallLogPop(1869);
1832  }
1833  catch(const Exception &e)
1834  {
1835  ErrorLog(180, e.Message);
1836  }
1837 }
1838 
1839 // ---------------------------------------------------------------------------
1840 void __fastcall TInterface::FontButtonClick(TObject *Sender)
1841 {
1842  try
1843  {
1844  TrainController->LogEvent("FontButtonClick");
1845  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FontButtonClick");
1846  FontDialog->Font = Display->GetFont(); //sets the dialog box font to the currently used font
1847  FontDialog->Execute(); //this displays the dialog box
1848  if(FontDialog->Font->Color == clB5G5R5) //white
1849  FontDialog->Font->Color = clB0G0R0; //black - don't store white in font, will display black as white on dark backgrounds
1850  Display->SetFont(FontDialog->Font); //sets the displayed font to the output from the dialog box
1851  if(TextBox->Visible)
1852  TextBox->SetFocus();
1853  else if(LocationNameTextBox->Visible)
1854  LocationNameTextBox->SetFocus();
1855  Utilities->CallLogPop(1172);
1856  }
1857  catch(const Exception &e)
1858  {
1859  ErrorLog(131, e.Message);
1860  }
1861 }
1862 
1863 // ---------------------------------------------------------------------------
1864 
1865 void __fastcall TInterface::ScreenGridButtonClick(TObject *Sender)
1866 {
1867  try
1868  {
1869  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenGridButtonClick");
1870  if(ScreenGridFlag)
1871  {
1872  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid off");
1873  ScreenGridFlag = false;
1874  }
1875  else
1876  {
1877  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid on");
1878  ScreenGridFlag = true;
1879  }
1881  Utilities->CallLogPop(89);
1882  }
1883  catch(const Exception &e)
1884  {
1885  ErrorLog(33, e.Message);
1886  }
1887 }
1888 
1889 // ---------------------------------------------------------------------------
1890 // PrefDir Interface
1891 // ---------------------------------------------------------------------------
1892 void __fastcall TInterface::PlanPrefDirsMenuItemClick(TObject *Sender) // Mode Menu Item
1893 {
1894  try
1895  {
1896  TrainController->LogEvent("PlanPrefDirsMenuItemClick");
1897  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PlanPrefDirsMenuItemClick");
1899  SetLevel1Mode(3);
1900  Utilities->CallLogPop(1173);
1901  }
1902  catch(const Exception &e)
1903  {
1904  ErrorLog(132, e.Message);
1905  }
1906 }
1907 
1908 // ---------------------------------------------------------------------------
1909 void __fastcall TInterface::AddPrefDirButtonClick(TObject *Sender)
1910 {
1911  try
1912  {
1913  TrainController->LogEvent("AddPrefDirButtonClick");
1914  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddPrefDirButtonClick");
1915  if(ConstructPrefDir->PrefDirSize() == 0)
1916  {
1917  ShowMessage("No preferred direction selection");
1918  Utilities->CallLogPop(22);
1919  return;
1920  }
1921  Screen->Cursor = TCursor(-11); // Hourglass;
1925  SetLevel1Mode(4);
1926  Screen->Cursor = TCursor(-2); // Arrow
1927  Utilities->CallLogPop(23);
1928  }
1929  catch(const Exception &e)
1930  {
1931  ErrorLog(10, e.Message);
1932  }
1933 }
1934 
1935 // ---------------------------------------------------------------------------
1936 void __fastcall TInterface::DeleteAllPrefDirButtonClick(TObject *Sender)
1937 {
1938  try
1939  {
1940  TrainController->LogEvent("DeleteAllPrefDirButtonClick");
1941  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteAllPrefDirButtonClick");
1942  TMsgDlgButtons Buttons;
1943  Buttons << mbYes << mbNo;
1944  if(MessageDlg("Do you really want to clear all preferred directions?", mtWarning, Buttons, 0) == mrNo)
1945  {
1946  Utilities->CallLogPop(24);
1947  return;
1948  }
1949  // leave all as was before pressed DeleteAllPrefDirButton
1950  else
1951  {
1956  SetLevel1Mode(5);
1957  }
1958  Utilities->CallLogPop(25);
1959  }
1960  catch(const Exception &e)
1961  {
1962  ErrorLog(11, e.Message);
1963  }
1964 }
1965 // ---------------------------------------------------------------------------
1966 
1967 void __fastcall TInterface::DeleteOnePrefDirButtonClick(TObject *Sender)
1968 {
1969  try
1970  {
1971  TrainController->LogEvent("DeleteOnePrefDirButtonClick");
1972  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteOnePrefDirButtonClick");
1973  ResetChangedFileDataAndCaption(18, false);
1974 // RlyFile = false; - don't alter this just for PrefDir changes
1975  Screen->Cursor = TCursor(-11); // Hourglass;
1976  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
1977  {
1980  }
1983  SetLevel1Mode(81); // all PrefDir truncated
1984  Screen->Cursor = TCursor(-2); // Arrow
1985  Utilities->CallLogPop(1591);
1986  }
1987  catch(const Exception &e)
1988  {
1989  ErrorLog(46, e.Message);
1990  }
1991 }
1992 
1993 // ---------------------------------------------------------------------------
1994 
1995 void __fastcall TInterface::ExitPrefDirButtonClick(TObject *Sender)
1996 {
1997  try
1998  {
1999  TrainController->LogEvent("ExitPrefDirButtonClick");
2000  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitPrefDirButtonClick");
2001  Level1Mode = BaseMode;
2002  SetLevel1Mode(6);
2003  Utilities->CallLogPop(1554);
2004  }
2005  catch(const Exception &e)
2006  {
2007  ErrorLog(133, e.Message);
2008  }
2009 }
2010 
2011 // ---------------------------------------------------------------------------
2012 // Operate Railway Interface
2013 // ---------------------------------------------------------------------------
2014 void __fastcall TInterface::OperateRailwayMenuItemClick(TObject *Sender) // Mode Menu Item
2015 {
2016  try
2017  {
2018  TrainController->LogEvent("OperateRailwayMenuItemClick");
2019  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateRailwayMenuItemClick");
2020  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
2021  AllRoutes->NextRouteID = 0; // reset to 0 whenever enter operating mode
2022  Level1Mode = OperMode;
2023  SetLevel1Mode(7);
2024  Utilities->CallLogPop(26);
2025  }
2026  catch(const Exception &e)
2027  {
2028  ErrorLog(12, e.Message);
2029  }
2030 }
2031 
2032 // ---------------------------------------------------------------------------
2033 void __fastcall TInterface::OperateButtonClick(TObject *Sender)
2034 {
2035  try
2036  {
2037  TrainController->LogEvent("StartOperationButtonClick");
2038  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateButtonClick");
2040  {
2042  SetLevel2OperMode(0);
2043  }
2044  else
2045  {
2047  SetLevel2OperMode(1);
2048  }
2049  Utilities->CallLogPop(1175);
2050  }
2051  catch(const Exception &e)
2052  {
2053  ErrorLog(37, e.Message);
2054  }
2055 }
2056 
2057 // ---------------------------------------------------------------------------
2058 void __fastcall TInterface::AutoSigsButtonClick(TObject *Sender)
2059  // must have PrefDirs to be available
2060 {
2061  try
2062  {
2063  TrainController->LogEvent("AutoSigsButtonClick");
2064  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AutoSigsButtonClick");
2065  AutoSigsFlag = true;
2066  PreferredRoute = true;
2067  ConsecSignalsRoute = true;
2068 
2069  AutoSigsButton->Enabled = false;
2070  SigPrefConsecButton->Enabled = true;
2071  SigPrefNonConsecButton->Enabled = true;
2072  UnrestrictedButton->Enabled = true;
2073 
2074  InfoPanel->Visible = true;
2075  if(Level2OperMode == PreStart)
2076  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2077  else
2078  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2079  InfoCaptionStore = InfoPanel->Caption;
2080  AutoRouteStartMarker->PlotOriginal(1, Display); // if overlay not plotted will ignore
2081  SigRouteStartMarker->PlotOriginal(2, Display); // if overlay not plotted will ignore
2082  NonSigRouteStartMarker->PlotOriginal(3, Display); // if overlay not plotted will ignore
2084  Utilities->CallLogPop(28);
2085  }
2086  catch(const Exception &e)
2087  {
2088  ErrorLog(14, e.Message);
2089  }
2090 }
2091 
2092 // ---------------------------------------------------------------------------
2093 
2094 void __fastcall TInterface::SigPrefConsecButtonClick(TObject *Sender)
2095  // must have PrefDirs to be available
2096 {
2097  try
2098  {
2099  TrainController->LogEvent("SigPrefButtonClick");
2100  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2101  AutoSigsFlag = false;
2102  PreferredRoute = true;
2103  ConsecSignalsRoute = true;
2104 
2105  AutoSigsButton->Enabled = true;
2106  SigPrefConsecButton->Enabled = false;
2107  SigPrefNonConsecButton->Enabled = true;
2108  UnrestrictedButton->Enabled = true;
2109 
2110  InfoPanel->Visible = true;
2111  if(Level2OperMode == PreStart)
2112  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2113  else
2114  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2115  InfoCaptionStore = InfoPanel->Caption;
2116  AutoRouteStartMarker->PlotOriginal(43, Display); // if overlay not plotted will ignore
2117  SigRouteStartMarker->PlotOriginal(44, Display); // if overlay not plotted will ignore
2118  NonSigRouteStartMarker->PlotOriginal(45, Display); // if overlay not plotted will ignore
2120  Utilities->CallLogPop(2265);
2121  }
2122  catch(const Exception &e)
2123  {
2124  ErrorLog(221, e.Message);
2125  }
2126 }
2127 
2128 //---------------------------------------------------------------------------
2129 
2130 void __fastcall TInterface::SigPrefNonConsecButtonClick(TObject *Sender)
2131  // must have PrefDirs to be available
2132 {
2133  try
2134  {
2135  TrainController->LogEvent("SigPrefButtonClick");
2136  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2137  AutoSigsFlag = false;
2138  PreferredRoute = true;
2139  ConsecSignalsRoute = false;
2140 
2141  AutoSigsButton->Enabled = true;
2142  SigPrefConsecButton->Enabled = true;
2143  SigPrefNonConsecButton->Enabled = false;
2144  UnrestrictedButton->Enabled = true;
2145 
2146  InfoPanel->Visible = true;
2147  if(Level2OperMode == PreStart)
2148  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2149  else
2150  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2151  InfoCaptionStore = InfoPanel->Caption;
2152  AutoRouteStartMarker->PlotOriginal(4, Display); // if overlay not plotted will ignore
2153  SigRouteStartMarker->PlotOriginal(5, Display); // if overlay not plotted will ignore
2154  NonSigRouteStartMarker->PlotOriginal(6, Display); // if overlay not plotted will ignore
2156  Utilities->CallLogPop(29);
2157  }
2158  catch(const Exception &e)
2159  {
2160  ErrorLog(15, e.Message);
2161  }
2162 }
2163 
2164 // ---------------------------------------------------------------------------
2165 void __fastcall TInterface::UnrestrictedButtonClick(TObject *Sender)
2166 {
2167  try
2168  {
2169  TrainController->LogEvent("NoSigNonPrefButtonClick");
2170  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NoSigNonPrefButtonClick");
2171  AutoSigsFlag = false;
2172  PreferredRoute = false;
2173  ConsecSignalsRoute = false;
2174  if(EveryPrefDir->PrefDirSize() > 0)
2175  {
2176  AutoSigsButton->Enabled = true;
2177  SigPrefConsecButton->Enabled = true;
2178  SigPrefNonConsecButton->Enabled = true;
2179  UnrestrictedButton->Enabled = false;
2180  }
2181  else
2182  {
2183  AutoSigsButton->Enabled = false;
2184  SigPrefConsecButton->Enabled = false;
2185  SigPrefNonConsecButton->Enabled = false;
2186  UnrestrictedButton->Enabled = false;
2187  }
2188  InfoPanel->Visible = true;
2189  if(Level2OperMode == PreStart)
2190  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2191  else
2192  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2193  InfoCaptionStore = InfoPanel->Caption;
2194  AutoRouteStartMarker->PlotOriginal(7, Display); // if overlay not plotted will ignore
2195  SigRouteStartMarker->PlotOriginal(8, Display); // if overlay not plotted will ignore
2196  NonSigRouteStartMarker->PlotOriginal(9, Display); // if overlay not plotted will ignore
2198  Utilities->CallLogPop(30);
2199  }
2200  catch(const Exception &e)
2201  {
2202  ErrorLog(16, e.Message);
2203  }
2204 }
2205 
2206 // ---------------------------------------------------------------------------
2207 void __fastcall TInterface::RouteCancelButtonClick(TObject *Sender)
2208 {
2209  try
2210  {
2211  TrainController->LogEvent("RouteCancelButtonClick");
2212  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RouteCancelButtonClick");
2213  RouteCancelFlag = true;
2214  InfoPanel->Visible = true;
2215  InfoPanel->Caption = "ROUTE CANCELLING: Right click on truncate element, first element to cancel (anywhere else to skip)";
2216  RouteCancelButton->Enabled = false;
2217  AutoRouteStartMarker->PlotOriginal(32, Display); // if overlay not plotted will ignore
2218  SigRouteStartMarker->PlotOriginal(33, Display); // if overlay not plotted will ignore
2219  NonSigRouteStartMarker->PlotOriginal(34, Display); // if overlay not plotted will ignore
2220  Utilities->CallLogPop(1176);
2221  }
2222  catch(const Exception &e)
2223  {
2224  ErrorLog(35, e.Message);
2225  }
2226 }
2227 
2228 // ---------------------------------------------------------------------------
2229 void __fastcall TInterface::PerformanceLogButtonClick(TObject *Sender)
2230 {
2231  try
2232  {
2233  TrainController->LogEvent("PerformanceLogButtonClick");
2234  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformanceLogButtonClick");
2236  {
2237  ShowPerformancePanel = true;
2238  PerformancePanel->Visible = true;
2239  PerformanceLogButton->Glyph->LoadFromResourceName(0, "HideLog");
2240  }
2241  else
2242  {
2243  ShowPerformancePanel = false;
2244  PerformancePanel->Visible = false;
2245  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2246  }
2247  Utilities->CallLogPop(1177);
2248  }
2249  catch(const Exception &e)
2250  {
2251  ErrorLog(36, e.Message);
2252  }
2253 }
2254 // ---------------------------------------------------------------------------
2255 
2256 void __fastcall TInterface::ExitOperationButtonClick(TObject *Sender)
2257 {
2258  try
2259  {
2260  TrainController->LogEvent("ExitOperationButtonClick");
2261  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitOperationButtonClick");
2263  {
2264  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
2265  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2267  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
2268  TrainController->BaseTime = TDateTime::CurrentDateTime();
2270  if(button == IDNO)
2271  {
2272  Utilities->CallLogPop(751);
2273  return;
2274  }
2275  }
2276  Track->ResetSignals(1);
2277  Track->ResetPoints(1);
2278  TrainController->SendPerformanceSummary(0, Utilities->PerformanceFile); // must come before trains finished becuase examines the train vectors
2279  Utilities->PerformanceFile.close();
2282  RouteMode = None;
2283  PreferredRoute = true; //default starting conditions
2284  ConsecSignalsRoute = true; //default starting conditions
2286  ShowPerformancePanel = false;
2287  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2288  ShowOperatorActionPanel = false; // new at v2.2.0
2289  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
2290  PerformanceLogBox->Lines->Clear();
2291  PerformancePanel->Visible = false;
2292  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
2293  PerformancePanel->Left = MainScreen->Left;
2294 // TipButton->Glyph->LoadFromResourceName(0, "ShowLog"); //'Trains in play' new at v2.2.0
2295  OAListBox->Clear();
2296  OperatorActionPanel->Visible = false;
2297  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height;
2298  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width; ;
2300  AllRoutes->LockedRouteVector.clear();
2301  Level1Mode = BaseMode;
2302  SetLevel1Mode(8); // calls Clearand...
2303  Utilities->CallLogPop(1555);
2304  }
2305  catch(const Exception &e)
2306  {
2307  ErrorLog(13, e.Message);
2308  }
2309 }
2310 
2311 // ---------------------------------------------------------------------------
2312 // Menu Interface (for items not already covered above)
2313 // ---------------------------------------------------------------------------
2314 void __fastcall TInterface::LoadRailwayMenuItemClick(TObject *Sender)
2315 {
2316  try
2317  {
2318  TrainController->LogEvent("LoadRailwayMenuItemClick");
2319  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadRailwayMenuItemClick");
2320  if(!ClearEverything(1))
2321  {
2322  Utilities->CallLogPop(1139);
2323  return;
2324  }
2325  // LoadRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly"; //as was
2326  // changed at v2.0.0 (Embarcadero change) to show all files together
2327  LoadRailwayDialog->Filter = "Railway files (*.rly or *.dev)|*.rly; *.dev";
2328  if(LoadRailwayDialog->Execute())
2329  {
2330  if(LoadRailwayDialog->InitialDir != TPath::GetDirectoryName(LoadRailwayDialog->FileName))//new at v2.6.0 to retain a new directory
2331  {
2332  LoadRailwayDialog->InitialDir = TPath::GetDirectoryName(LoadRailwayDialog->FileName);
2333  SaveRailwayDialog->InitialDir = TPath::GetDirectoryName(LoadRailwayDialog->FileName);
2334  }
2335  TrainController->LogEvent("LoadRailway " + AnsiString(LoadRailwayDialog->FileName));
2336  LoadRailway(0, AnsiString(LoadRailwayDialog->FileName));
2337  }
2338  // else ShowMessage("Load Aborted"); drop this
2339  // Display->Update(); //display updated in ClearandRebuildRailway
2340  Track->CalcHLocMinEtc(9);
2341  Level1Mode = BaseMode;
2344  SetLevel1Mode(11); // calls Clearand... to plot the new railway
2345  Utilities->CallLogPop(31);
2346  }
2347  catch(const Exception &e)
2348  {
2349  ErrorLog(17, e.Message);
2350  }
2351 }
2352 // ---------------------------------------------------------------------------
2353 
2354 void TInterface::LoadRailway(int Caller, AnsiString LoadFileName)
2355 { // display of the loaded railway covered in the calling routine
2356  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRailway," + LoadFileName);
2357  if(FileIntegrityCheck(0, LoadFileName.c_str()))
2358  {
2359  Screen->Cursor = TCursor(-11); // Hourglass;
2360  std::ifstream VecFile(LoadFileName.c_str());
2361  if(!(VecFile.fail()))
2362  {
2363  AnsiString TempString = Utilities->LoadFileString(VecFile); // version number
2364  int TempOffsetHHome = Utilities->LoadFileInt(VecFile);
2365  int TempOffsetVHome = Utilities->LoadFileInt(VecFile);
2366  bool GraphicsFollow = false;
2367  // can't load DisplayOffsetH & VHome until after LoadTrack as that calls TrackClear & zeroes them
2368 // load track elements
2369  Track->LoadTrack(1, VecFile, GraphicsFollow);
2370 // load text elements
2371  TextHandler->LoadText(0, VecFile);
2372 // load PrefDir elements
2373  EveryPrefDir->LoadPrefDir(0, VecFile);
2374  if(GraphicsFollow)
2375  {
2376 // load user graphics
2377  Track->LoadGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder
2378  }
2379  EveryPrefDir->CheckPrefDirAgainstTrackVector(0); // clears PrefDir if any discrepancies found
2380  VecFile.close();
2381  Display->DisplayOffsetHHome = TempOffsetHHome;
2382  Display->DisplayOffsetVHome = TempOffsetVHome;
2384 
2385  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
2386  TempFont->Style.Clear();
2387  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
2388  TempFont->Size = 10;
2389  TempFont->Color = clB0G0R0;
2390  TempFont->Charset = (TFontCharset)(0);
2391  MainScreen->Canvas->Font->Assign(TempFont);
2392  delete TempFont;
2393 
2394 // calculate starting zoomed out offset values - same as when zoom out button clicked
2395  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
2396 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
2397  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
2398  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
2399  if((LeftExcess > 0) && (RightExcess > 0))
2400  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
2401  else if((LeftExcess > 0) && (RightExcess <= 0))
2402  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
2403  (Utilities->ScreenElementWidth / 2); // normalise to nearest half screen
2404  else if((LeftExcess <= 0) && (RightExcess > 0))
2405  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
2406  else
2407  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
2408 
2409  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
2410  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
2411  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
2412  if((TopExcess > 0) && (BotExcess > 0))
2413  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
2414  else if((TopExcess > 0) && (BotExcess <= 0))
2415  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
2416  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
2417  else if((TopExcess <= 0) && (BotExcess > 0))
2418  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
2419  else
2420  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
2421 // all above same as when zoom out button clicked
2422  Display->DisplayZoomOutOffsetVHome = Display->DisplayZoomOutOffsetV; // now set zoomed out 'home' values
2424 
2425  SavedFileName = AnsiString(LoadRailwayDialog->FileName); // includes the full PrefDir
2426  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
2427  {
2428  Track->DuplicatedLocationName(1, true);
2429  char LastChar = SavedFileName[SavedFileName.Length()];
2430  if((LastChar == 'y') || (LastChar == 'Y'))
2431  {
2432  if(!(Track->IsReadyForOperation(false)))
2433  {
2434  ShowMessage("Railway not ready for operation so unable to load as a .rly file. Loading as a new railway under development");
2435  SavedFileName = "";
2436  RlyFile = false;
2437  RailwayTitle = "";
2438  TimetableTitle = "";
2439  SetCaption(5);
2440  Track->CalcHLocMinEtc(1);
2441  Screen->Cursor = TCursor(-2); // Arrow
2442  Level1Mode = BaseMode;
2443  SetLevel1Mode(9);
2444  Utilities->CallLogPop(1136);
2445  return;
2446  }
2447  else
2448  {
2449  RlyFile = true;
2450  }
2451  }
2452  else
2453  {
2454  RlyFile = false;
2455  }
2456  }
2457  else
2458  {
2459  RlyFile = false;
2460  }
2461  FileChangedFlag = false;
2462  for(int x = AnsiString(LoadRailwayDialog->FileName).Length(); x > 0; x--)
2463  {
2464  if(AnsiString(LoadRailwayDialog->FileName)[x] == '\\')
2465  {
2466  RailwayTitle = AnsiString(LoadRailwayDialog->FileName).SubString(x + 1, AnsiString(LoadRailwayDialog->FileName).Length() - x - 4);
2467  TimetableTitle = "";
2468  SetCaption(6);
2469  break;
2470  }
2471  }
2472  } // if(VecFile)
2473  else
2474  ShowMessage("File open failed prior to load");
2475  Screen->Cursor = TCursor(-2); // Arrow
2476  } // if(FileIntegrityCheck(LoadRailwayDialog->FileName.c_str()))
2477  else
2478  ShowMessage("File integrity check failed - unable to load");
2479  Utilities->CallLogPop(1774);
2480 }
2481 
2482 // ---------------------------------------------------------------------------
2483 
2484 void __fastcall TInterface::SaveMenuItemClick(TObject *Sender)
2485 {
2486 // save under existing name
2487 // no need to alter RlyFile for saving under existing name
2488 
2489  try
2490  {
2491  TrainController->LogEvent("SaveMenuItemClick, " + SavedFileName);
2492  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveMenuItemClick");
2493  Screen->Cursor = TCursor(-11); // Hourglass;
2494  std::ofstream VecFile(SavedFileName.c_str());
2495  if(!(VecFile.fail()))
2496  {
2500  // save track elements
2501  if(Track->UserGraphicVector.empty())
2502  {
2503  Track->SaveTrack(3, VecFile, false); // false for no graphics (**Active elements** saved as marker)
2504  }
2505  else
2506  {
2507  Track->SaveTrack(8, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
2508  }
2509  // save text elements
2510  TextHandler->SaveText(0, VecFile);
2511  // save PrefDir elements
2512  EveryPrefDir->SavePrefDirVector(0, VecFile);
2513  if(!Track->UserGraphicVector.empty())
2514  {
2515  // save user graphics
2516  Track->SaveUserGraphics(0, VecFile);
2517  }
2518  FileChangedFlag = false;
2519  VecFile.close();
2520  }
2521  else
2522  ShowMessage("File open failed prior to save");
2523  Screen->Cursor = TCursor(-2); // Arrow
2524  Level1Mode = BaseMode;
2525  SetLevel1Mode(12); // to disable the save option
2526  Utilities->CallLogPop(1178);
2527  }
2528  catch(const Exception &e)
2529  {
2530  ErrorLog(135, e.Message);
2531  }
2532 }
2533 
2534 // ---------------------------------------------------------------------------
2535 void __fastcall TInterface::SaveAsMenuItemClick(TObject *Sender)
2536 {
2537  try
2538  {
2539  TrainController->LogEvent("SaveAsMenuItemClick");
2540  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveAsMenuItemClick");
2541  SaveAsSubroutine(0);
2542  Utilities->CallLogPop(32);
2543  }
2544  catch(const Exception &e)
2545  {
2546  ErrorLog(18, e.Message);
2547  }
2548 }
2549 
2550 // ---------------------------------------------------------------------------
2551 
2552 void __fastcall TInterface::SaveImageNoGridMenuItemClick(TObject *Sender)
2553 { // need to stop clock in case invoke during operation
2554  try
2555  {
2556  TrainController->LogEvent("SaveImageNoGridMenuItemClick");
2557  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageNoGridMenuItemClick");
2558  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2559  {
2560  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2561  Utilities->CallLogPop(1695);
2562  return;
2563  }
2564  Screen->Cursor = TCursor(-11); // Hourglass;
2565  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2567  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2568  // format "16/06/2009 20:55:17"
2569  // avoid characters in filename:= / \ : * ? " < > |
2570  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2571  AnsiString ShortName = "";
2572  for(int x = ImageFileName.Length(); x > 0; x--)
2573  {
2574  if(ImageFileName[x] == '\\')
2575  {
2576  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2577  break;
2578  }
2579  }
2580  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2581  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2582  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2583 
2584  int HPosMin = Track->GetHLocMin() * 16;
2585  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2586  int VPosMin = Track->GetVLocMin() * 16;
2587  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2588  RailwayImage->Width = HPosMax - HPosMin;
2589  RailwayImage->Height = VPosMax - VPosMin;
2590 
2591  // need to check if there is any text that extends past HPosMax or below VPosMax
2592  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2593  if(!TextHandler->TextVector.empty())
2594  {
2595  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2596  {
2597  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2598  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2599  if(NewWidth > RailwayImage->Width)
2600  {
2601  RailwayImage->Width = NewWidth;
2602  }
2603  if(NewHeight > RailwayImage->Height)
2604  {
2605  RailwayImage->Height = NewHeight;
2606  }
2607  }
2608  }
2609 
2610  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2611  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2612  RailwayImage->Canvas->FillRect(Rect);
2613 
2614  // write graphics first so text & track overwrite
2615  Track->WriteGraphicsToImage(0, RailwayImage);
2616  // then write text so track overwrites
2617  TextHandler->WriteTextToImage(0, RailwayImage);
2618  Track->WriteTrackToImage(0, RailwayImage);
2619 
2620  RailwayImage->SaveToFile(ImageFileName);
2621  delete RailwayImage;
2622  TrainController->BaseTime = TDateTime::CurrentDateTime();
2624  Screen->Cursor = TCursor(-2); // Arrow
2625  Utilities->CallLogPop(1535);
2626  }
2627  catch(const Exception &e)
2628  {
2629  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2630  {
2631  Screen->Cursor = TCursor(-2); // Arrow;
2632  UnicodeString MessageStr = "Insufficient memory available to store this image";
2633  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2634  }
2635  else
2636  {
2637  ErrorLog(42, e.Message);
2638  }
2639  }
2640 }
2641 
2642 // ---------------------------------------------------------------------------
2643 
2644 void __fastcall TInterface::SaveImageAndGridMenuItemClick(TObject *Sender)
2645 { // need to stop clock in case invoke during operation
2646  try
2647  {
2648  TrainController->LogEvent("SaveImageAndGridMenuItemClick");
2649  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndGridMenuItemClick");
2650  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2651  {
2652  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2653  Utilities->CallLogPop(1696);
2654  return;
2655  }
2656  Screen->Cursor = TCursor(-11); // Hourglass;
2657  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2659  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2660  // format "16/06/2009 20:55:17"
2661  // avoid characters in filename:= / \ : * ? " < > |
2662  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2663  AnsiString ShortName = "";
2664  for(int x = ImageFileName.Length(); x > 0; x--)
2665  {
2666  if(ImageFileName[x] == '\\')
2667  {
2668  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2669  break;
2670  }
2671  }
2672  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2673  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2674  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2675  int HPosMin = Track->GetHLocMin() * 16;
2676  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2677  int VPosMin = Track->GetVLocMin() * 16;
2678  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2679  RailwayImage->Width = HPosMax - HPosMin;
2680  RailwayImage->Height = VPosMax - VPosMin;
2681 
2682  // need to check if there is any text that extends past HPosMax or below VPosMax
2683  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2684  if(!TextHandler->TextVector.empty())
2685  {
2686  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2687  {
2688  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2689  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2690  if(NewWidth > RailwayImage->Width)
2691  {
2692  RailwayImage->Width = NewWidth;
2693  }
2694  if(NewHeight > RailwayImage->Height)
2695  {
2696  RailwayImage->Height = NewHeight;
2697  }
2698  }
2699  }
2700 
2701  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2702  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2703  RailwayImage->Canvas->FillRect(Rect);
2704 
2705  // write the grid first so all else on top
2706  for(int x = 0; x < ((RailwayImage->Width) / 16); x++)
2707  {
2708  for(int y = 0; y < ((RailwayImage->Height) / 16); y++)
2709  {
2710  RailwayImage->Canvas->Draw((x * 16), (y * 16), RailGraphics->bmGrid); // graphic is black on white so no need to change
2711  }
2712  }
2713  // write graphics next so text & track overwrite
2714  Track->WriteGraphicsToImage(1, RailwayImage);
2715  // then write text so track overwrites
2716  TextHandler->WriteTextToImage(1, RailwayImage);
2717  Track->WriteTrackToImage(1, RailwayImage);
2718  RailwayImage->SaveToFile(ImageFileName);
2719  delete RailwayImage;
2720  TrainController->BaseTime = TDateTime::CurrentDateTime();
2722  Screen->Cursor = TCursor(-2); // Arrow
2723  Utilities->CallLogPop(1536);
2724  }
2725  catch(const Exception &e)
2726  {
2727  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2728  {
2729  Screen->Cursor = TCursor(-2); // Arrow;
2730  UnicodeString MessageStr = "Insufficient memory available to store this image";
2731  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2732  }
2733  else
2734  {
2735  ErrorLog(43, e.Message);
2736  }
2737  }
2738 }
2739 // ---------------------------------------------------------------------------
2740 
2741 void __fastcall TInterface::SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
2742 { // need to stop clock in case invoke during operation
2743  try
2744  {
2745  TrainController->LogEvent("SaveImageAndPrefDirsMenuItemClick");
2746  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndPrefDirsMenuItemClick");
2747  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2748  {
2749  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2750  Utilities->CallLogPop(1697);
2751  return;
2752  }
2753  Screen->Cursor = TCursor(-11); // Hourglass;
2754  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2756  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2757  // format "16/06/2009 20:55:17"
2758  // avoid characters in filename:= / \ : * ? " < > |
2759  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2760  AnsiString ShortName = "";
2761  for(int x = ImageFileName.Length(); x > 0; x--)
2762  {
2763  if(ImageFileName[x] == '\\')
2764  {
2765  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2766  break;
2767  }
2768  }
2769  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2770  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2771  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2772  int HPosMin = Track->GetHLocMin() * 16;
2773  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2774  int VPosMin = Track->GetVLocMin() * 16;
2775  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2776  RailwayImage->Width = HPosMax - HPosMin;
2777  RailwayImage->Height = VPosMax - VPosMin;
2778 
2779  // need to check if there is any text that extends past HPosMax or below VPosMax
2780  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2781  if(!TextHandler->TextVector.empty())
2782  {
2783  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2784  {
2785  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2786  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2787  if(NewWidth > RailwayImage->Width)
2788  {
2789  RailwayImage->Width = NewWidth;
2790  }
2791  if(NewHeight > RailwayImage->Height)
2792  {
2793  RailwayImage->Height = NewHeight;
2794  }
2795  }
2796  }
2797 
2798  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2799  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2800  RailwayImage->Canvas->FillRect(Rect);
2801 
2802  // write graphics first so text & track overwrite
2803  Track->WriteGraphicsToImage(2, RailwayImage);
2804  // then write text so track overwrites
2805  TextHandler->WriteTextToImage(2, RailwayImage);
2806  Track->WriteTrackToImage(2, RailwayImage);
2807  EveryPrefDir->WritePrefDirToImage(0, RailwayImage);
2808  RailwayImage->SaveToFile(ImageFileName);
2809  delete RailwayImage;
2810  TrainController->BaseTime = TDateTime::CurrentDateTime();
2812  Screen->Cursor = TCursor(-2); // Arrow
2813  Utilities->CallLogPop(1566);
2814  }
2815  catch(const Exception &e)
2816  {
2817  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2818  {
2819  Screen->Cursor = TCursor(-2); // Arrow;
2820  UnicodeString MessageStr = "Insufficient memory available to store this image";
2821  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2822  }
2823  else
2824  {
2825  ErrorLog(45, e.Message);
2826  }
2827  }
2828 }
2829 // ---------------------------------------------------------------------------
2830 
2831 void __fastcall TInterface::SaveOperatingImageMenuItemClick(TObject *Sender)
2832 { // need to stop clock
2833  try
2834  {
2835  TrainController->LogEvent("SaveOperatingImageMenuItemClick");
2836  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveOperatingImageMenuItemClick");
2837  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2838  {
2839  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2840  Utilities->CallLogPop(1702);
2841  return;
2842  }
2843  Screen->Cursor = TCursor(-11); // Hourglass;
2844  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2846 
2847  AnsiString TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
2848  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
2849  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2850  // format "16/06/2009 20:55:17"
2851  // avoid characters in filename:= / \ : * ? " < > |
2852  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
2853  "; " + TimetableTitle + ".bmp";
2854  AnsiString ShortName = "";
2855  for(int x = ImageFileName.Length(); x > 0; x--)
2856  {
2857  if(ImageFileName[x] == '\\')
2858  {
2859  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2860  break;
2861  }
2862  }
2863  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2864  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2865  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2866  int HPosMin = Track->GetHLocMin() * 16;
2867  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2868  int VPosMin = Track->GetVLocMin() * 16;
2869  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2870  RailwayImage->Width = HPosMax - HPosMin;
2871  RailwayImage->Height = VPosMax - VPosMin;
2872 
2873  // need to check if there is any text that extends past HPosMax or below VPosMax
2874  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2875  if(!TextHandler->TextVector.empty())
2876  {
2877  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2878  {
2879  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2880  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2881  if(NewWidth > RailwayImage->Width)
2882  {
2883  RailwayImage->Width = NewWidth;
2884  }
2885  if(NewHeight > RailwayImage->Height)
2886  {
2887  RailwayImage->Height = NewHeight;
2888  }
2889  }
2890  }
2891 
2892  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2893  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2894  RailwayImage->Canvas->FillRect(Rect);
2895 
2896  // write graphics first so text & track overwrite
2897  Track->WriteGraphicsToImage(3, RailwayImage);
2898  // then write text so track overwrites
2899  TextHandler->WriteTextToImage(3, RailwayImage);
2900  Track->WriteOperatingTrackToImage(0, RailwayImage); // need points with single fillets, signals with colours, gaps all connected
2901  AllRoutes->WriteAllRoutesToImage(0, RailwayImage);
2902 // add any locked route markers
2903  if(!AllRoutes->LockedRouteVector.empty())
2904  {
2905  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
2906  {
2907  TOneRoute Route = AllRoutes->GetFixedRouteAt(167, LRVIT->RouteNumber);
2908  int x = Route.PrefDirSize() - 1;
2909  bool BreakFlag = false;
2910  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(188, x);
2911  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
2912  {
2913  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
2914  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
2915  if(!(AllRoutes->TrackIsInARoute(13, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
2916  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
2917  {
2918  BreakFlag = true;
2919  break; // train removed earlier element from route so stop here
2920  }
2921  x--;
2922  PrefDirElement = Route.GetFixedPrefDirElementAt(180, x);
2923  }
2924  if(!BreakFlag)
2925  {
2926  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
2927  {
2928  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
2929  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
2930  }
2931  }
2932  }
2933  }
2934  TrainController->WriteTrainsToImage(0, RailwayImage);
2935  RailwayImage->SaveToFile(ImageFileName);
2936  delete RailwayImage;
2937  TrainController->BaseTime = TDateTime::CurrentDateTime();
2939  Screen->Cursor = TCursor(-2); // Arrow
2940  Utilities->CallLogPop(1703);
2941  }
2942  catch(const Exception &e)
2943  {
2944  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2945  {
2946  Screen->Cursor = TCursor(-2); // Arrow;
2947  UnicodeString MessageStr = "Insufficient memory available to store this image";
2948  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2949  }
2950  else
2951  {
2952  ErrorLog(113, e.Message); //NB: DO NOT CHANGE THIS ERROR NUMBER - THE DISPLAYED MESSAGE DEPENDS ON IT
2953  }
2954  }
2955 }
2956 
2957 // ---------------------------------------------------------------------------
2958 
2959 void __fastcall TInterface::SaveHeaderMenu1Click(TObject *Sender)
2960 {
2961 //
2962  try
2963  {
2964  TrainController->LogEvent("SaveHeaderMenu1Click");
2965  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveHeaderMenu1Click");
2966  if(Sender == SaveSessionButton)
2967  {
2968  SaveSessionFlag = true;
2969  }
2970  else if(SavedFileName == "") // use 'Save As' function
2971  {
2972  SaveAsSubroutine(1);
2973  }
2974  else // ordinary save
2975  {
2976  Screen->Cursor = TCursor(-11); // Hourglass;
2977  std::ofstream VecFile(SavedFileName.c_str());
2978  if(!(VecFile.fail()))
2979  {
2983  // save track elements
2984  if(Track->UserGraphicVector.empty())
2985  {
2986  Track->SaveTrack(9, VecFile, false); // false for no graphics (**Active elements** saved as marker)
2987  }
2988  else
2989  {
2990  Track->SaveTrack(10, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
2991  }
2992  // save text elements
2993  TextHandler->SaveText(5, VecFile);
2994  // save PrefDir elements
2995  EveryPrefDir->SavePrefDirVector(8, VecFile);
2996  if(!Track->UserGraphicVector.empty())
2997  {
2998  // save user graphics
2999  Track->SaveUserGraphics(1, VecFile);
3000  }
3001  FileChangedFlag = false;
3002  VecFile.close();
3003  }
3004  else
3005  ShowMessage("Railway failed to save - can't open file");
3006  Screen->Cursor = TCursor(-2); // Arrow
3007  }
3008  Utilities->CallLogPop(1552);
3009  }
3010  catch(const Exception &e)
3011  {
3012  ErrorLog(44, e.Message);
3013  }
3014 }
3015 
3016 // ---------------------------------------------------------------------------
3017 void __fastcall TInterface::LoadSessionMenuItemClick(TObject *Sender)
3018 {
3019  try
3020  {
3021  TrainController->LogEvent("LoadSessionMenuItemClick");
3022  LoadSessionFlag = true; // load session within ClockTimer2
3023  }
3024  catch(const Exception &e)
3025  {
3026  ErrorLog(136, e.Message);
3027  }
3028 }
3029 
3030 // ---------------------------------------------------------------------------
3031 void __fastcall TInterface::ClearAllMenuItemClick(TObject *Sender)
3032 {
3033  try
3034  {
3035  TrainController->LogEvent("ClearAllMenuItemClick");
3036  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClearAllMenuItemClick");
3037  if(ClearEverything(2))
3038  {;
3039  } // no change in action on result
3040  Level1Mode = BaseMode;
3041  SetLevel1Mode(126);
3042  Utilities->CallLogPop(1179);
3043  }
3044  catch(const Exception &e)
3045  {
3046  ErrorLog(137, e.Message);
3047  }
3048 }
3049 
3050 // ---------------------------------------------------------------------------
3051 void __fastcall TInterface::ExportTTMenuItemClick(TObject *Sender)
3052 { // no need to stop clock as can't be called when railway operating
3053  try
3054  {
3055  TrainController->LogEvent("ExportTTMenuItemClick");
3056  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTMenuItemClick");
3057  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
3058  {
3059  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
3060  Utilities->CallLogPop(1699);
3061  return;
3062  }
3063 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
3064 // the message instead, but reset here afterwards
3065  // no need to stop clock as can't select this if operating
3067  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
3068  Utilities->CallLogPop(1573);
3069  }
3070  catch(const Exception &e)
3071  {
3072  ErrorLog(138, e.Message);
3073  }
3074 }
3075 // ---------------------------------------------------------------------------
3076 // Timetable editing functions
3077 
3078 /* Note that during early development the timetable was created outside the program as a .csv file using Excel, it was only later that
3079  the editing functions within the program were developed. Much of the original structure was preserved though to avoid rewriting the
3080  code interpretation functions in TrainUnit.cpp. This is why commas are used as service event separators, and why it is necessary to
3081  convert them to CRLFs for display and back again for internal storage. It is acknowledged that all this makes the editing functions
3082  somewhat cumbersome, and, as ever, if I was starting again I wouldn't do it like that!
3083 
3084  CR & LF review:
3085  These cause problems by the way that different subroutines handle them.
3086 
3087  AnsiStrings can incorporate CRLFs, but the end of an AnsiString is marked by a '\0' character as in 'C' strings.
3088 
3089  In the fstream functions 'getline(char_type* s, streamsize n)' extracts characters from the stream and puts them in buffer 's' until
3090  (a) n-1 characters are stored + '\0' after the n-1 characters;
3091  (b) a '\n' (CRLF) character is found in the stream, in which case a '\0' is added to the buffer after the text that immediately
3092  precedes the CRLF in the stream; and
3093  (c) an eof() is found in the stream, in which case a '\0' is added to the buffer at the end of the text.
3094  Note that if no characters are stored a '\0' is still stored in position [0] of the buffer.
3095 
3096  The << operator in ofstreams, when used with a null terminated string, doesn't store the null. If it is required it has to be
3097  sent explicitly, e.g. file << '\0'. Presumably the same applies for CRLF terminated strings.
3098 
3099 */
3100 // ---------------------------------------------------------------------------
3101 
3102 void __fastcall TInterface::CreateTimetableMenuItemClick(TObject *Sender)
3103 {
3104  try
3105  {
3106  TrainController->LogEvent("CreateTimetableMenuItemClick");
3107  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CreateTimetableMenuItemClick");
3108  CreateEditTTFileName = "";
3109  TimetableEditVector.clear();
3110  TimetableEditPanel->Visible = true;
3111  TrainController->TTEditPanelVisible = true; //added at v2.6.0 for two location message
3112  HighlightPanel->Visible = false;
3113  TimetablePanel->Visible = true;
3114  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3115  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3116  OneEntryTimetableMemo->Clear();
3117  AllEntriesTTListBox->Clear();
3118  TTStartTimeBox->Text = "";
3119  AddSubMinsBox->Text = "";
3121  LocationNameComboBox->Clear();
3122  TimetableTitle = ""; // unload any loaded timetable. Added here at v2.1.0
3123  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Added here at v2.1.0
3124  SetCaption(9); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3125  TimetableChangedFlag = false;
3126  TimetableValidFlag = false;
3127  TTEntryChangedFlag = false;
3129  AZOrderButton->Caption = AnsiString("A-Z Order");
3130  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3131  CopiedEntryFlag = false;
3132  NewEntryInPreparationFlag = false;
3133  CopiedEntryStr = "";
3134  TEVPtr = 0;
3136  TTFirstServicePtr = 0;
3137  TTLastServicePtr = 0; // all set to null to begin with
3138 
3139 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3140  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3142  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3143  {
3144  if((Track->TrackVector.at(x).ActiveTrackElementName != "") && (Track->ContinuationNameMap.find(Track->TrackVector.at(x).ActiveTrackElementName))
3145  == Track->ContinuationNameMap.end())
3146  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3147  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
3148  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3149  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3150  }
3151  }
3153  if(!(Track->ActiveTrackElementNameMap.empty()))
3154  {
3155  LocationNameComboBox->Text = "Location names";
3156 // new version at beta v0.2b
3158  ATENIT++)
3159  {
3160  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3161  // continuations as well as other track will be included - earlier version
3162  // would have excluded them
3163  }
3164 
3165 /* old version using LocationNameMultiMap, changed to use ActiveTrackElementNames to avoid including lone concourses and named non-station
3166  locations
3167  TStringList *StringList = new TStringList;
3168  StringList->Clear();//probably already empty but help file doesn't say so
3169  StringList->Sorted = false;//for now
3170  for(TTrack::TLocationNameMultiMapIterator LNMIT = Track->LocationNameMultiMap.begin(); LNMIT != Track->LocationNameMultiMap.end(); LNMIT++)
3171  {
3172  NewKey = LNMIT->first;
3173  if(OldKey != NewKey)//only add new values
3174  {
3175  if(Track->ContinuationNameMap.find(NewKey) == Track->ContinuationNameMap.end())//not a continuation
3176  {
3177  StringList->Add(NewKey);
3178  OldKey = NewKey;
3179  }
3180  }
3181  }
3182  StringList->Sort();
3183  for(int x=0;x<StringList->Count;x++)
3184  {
3185  LocationNameComboBox->Items->Add(StringList->Strings[x]);
3186  }
3187  delete StringList;
3188 */
3189  }
3190  else
3191  {
3192  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3193  }
3195  SetLevel1Mode(82);
3196  Utilities->CallLogPop(1595);
3197  }
3198  catch(const Exception &e)
3199  {
3200  ErrorLog(47, e.Message);
3201  }
3202 }
3203 
3204 // ---------------------------------------------------------------------------
3205 void __fastcall TInterface::EditTimetableMenuItemClick(TObject *Sender)
3206 /* The .ttb file contains a sequence of AnsiStrings separated by null characters. CRLFs may be embedded within the AnsiStrings,
3207  * to cause newlines when displayed. Each AnsiString corresponds to a timetable 'entry'
3208 */
3209 {
3210  try
3211  {
3212  TrainController->LogEvent("EditTimetableMenuItemClick");
3213  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EditTimetableMenuItemClick");
3214  SigImagePanel->Visible = false; //stop panel showing while waiting for name entry
3215  TimetableDialog->Filter = "Timetable file (*.ttb)|*ttb";
3216  CreateEditTTFileName = "";
3217  TimetableEditVector.clear();
3218  TimetableEditPanel->Visible = true;
3219  TrainController->TTEditPanelVisible = true; //added at v2.6.0 for two location message
3220  HighlightPanel->Visible = false;
3221  TimetablePanel->Visible = true;
3222  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3223  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3224  OneEntryTimetableMemo->Clear();
3225  AllEntriesTTListBox->Clear();
3226  TTStartTimeBox->Text = "";
3227  AddSubMinsBox->Text = "";
3229  LocationNameComboBox->Clear();
3230  TimetableTitle = ""; // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3231  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3232  SetCaption(8); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3233  TEVPtr = 0;
3235  TTFirstServicePtr = 0;
3236  TTLastServicePtr = 0; // all set to null to begin with
3237  if(TimetableDialog->Execute())
3238  {
3239  if(TimetableDialog->InitialDir != TPath::GetDirectoryName(TimetableDialog->FileName))//new at v2.6.0 to retain a new directory
3240  {
3241  TimetableDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
3242  SaveTTDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
3243  }
3244  CreateEditTTFileName = AnsiString(TimetableDialog->FileName);
3245  TrainController->LogEvent("EditTimetable " + CreateEditTTFileName);
3246  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary); // open in binary to examine each character
3247  if(TTBLFile.is_open())
3248  {
3249  // check doesn't contain any non-ascii characters except CR, LF & '\0', and isn't empty
3250  char c;
3251  while(!TTBLFile.eof())
3252  {
3253  TTBLFile.get(c);
3254  if((c < 32) && (c != 13) && (c != 10) && (c != '\0')) // char is signed by default so values > 127 will be caught as treated as -ve
3255  {
3256  ShowMessage("Timetable file is empty or contains non-ascii characters, codes must be between 20 and 127, or CR or LF");
3257  TTBLFile.close();
3258  Utilities->CallLogPop(1612);
3259  return;
3260  }
3261  }
3262  TTBLFile.close();
3263  }
3264  else
3265  {
3266  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
3267  Utilities->CallLogPop(1597);
3268  return;
3269  }
3270  // reopen again in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
3271  Delay(4, 100); // 100mSec delay between closing & re-opening file
3272  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary);
3273  if(TTBLFile.is_open())
3274  {
3275  TTBLFile.clear(); // to clear eofbit from last read
3276  TTBLFile.seekg(0); // shouldn't be needed but include for safety
3277  TimetableChangedFlag = false;
3278  TimetableValidFlag = false;
3279  TTEntryChangedFlag = false;
3281  AZOrderButton->Caption = AnsiString("A-Z Order");
3282  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3283  NewEntryInPreparationFlag = false;
3284  CopiedEntryStr = "";
3285  CopiedEntryFlag = false;
3286 // CreateEditTTFileName = TimetableDialog->FileName;
3287  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
3288  {
3289  if(CreateEditTTFileName[x] == '\\')
3290  {
3291  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
3292  break;
3293  }
3294  }
3295  char *TimetableEntryString = new char[10000];
3296  while(true)
3297  {
3298  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
3299  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
3300  { // may still have eof even if read a line, and
3301  // if so need to process it
3302  break;
3303  }
3304  AnsiString OneLine(TimetableEntryString);
3305  TimetableEditVector.push_back(OneLine);
3306  }
3307  TTBLFile.close();
3308  delete TimetableEntryString;
3309  // here with TimetableEditVector compiled
3310  }
3311  else
3312  {
3313  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
3314  Utilities->CallLogPop(1654);
3315  return;
3316  }
3317  }
3318  else // cancelled dialog [section prior to CallLogPop added for v1.3.2 to clear timetable screen if cancel button pressed]
3319  {
3320  CreateEditTTFileName = "";
3321 // set to null to allow a check during error file saving, if not null save the tt being edited to the file (see entry in ExitTTModeButtonClick)
3322  CreateEditTTTitle = ""; // as above
3323  Level1Mode = BaseMode;
3324  SetLevel1Mode(132);
3325  Utilities->CallLogPop(1633);
3326  return;
3327  }
3328 
3330  if(TimetableEditVector.empty())
3331  {
3333  SetLevel1Mode(89);
3334  Utilities->CallLogPop(1614);
3335  return;
3336  }
3337 
3338 // all now set where can be
3340 
3341 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3342  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3344  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3345  {
3346  if((Track->TrackVector.at(x).ActiveTrackElementName != "") && (Track->ContinuationNameMap.find(Track->TrackVector.at(x).ActiveTrackElementName))
3347  == Track->ContinuationNameMap.end())
3348  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3349  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
3350  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3351  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3352  }
3353  }
3355  if(!(Track->ActiveTrackElementNameMap.empty()))
3356  {
3357  LocationNameComboBox->Text = "Location names";
3358 // new version for beta v0.2b
3360  ATENIT++)
3361  {
3362  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3363  // continuations as well as other track will be included - earlier version
3364  // would have excluded them
3365  }
3366  }
3367  else
3368  {
3369  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3370  }
3372  SetLevel1Mode(83);
3373  Utilities->CallLogPop(1596);
3374  }
3375  catch(const Exception &e)
3376  {
3377  ErrorLog(48, e.Message);
3378  }
3379 }
3380 // ---------------------------------------------------------------------------
3381 
3382 void __fastcall TInterface::ShowHideTTButtonClick(TObject *Sender)
3383 {
3384  try
3385  {
3386  TrainController->LogEvent("ShowHideTTButtonClick");
3387  if(TimetableEditPanel->Visible)
3388  {
3389  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Show");
3390  TimetableEditPanel->Visible = false;
3391  TrainController->TTEditPanelVisible = false; //added at v2.6.0 for two location message
3392  ShowHideTTButton->Hint = "Show the timetable editor Shift S";
3393 // InfoPanel->Visible = false; //changed at v1.3.0 to make it clearer that still in TT mode
3394  InfoPanel->Caption = "Timetable mode: editor hidden"; // as above
3395  }
3396  else
3397  {
3398  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3399  TimetableEditPanel->Visible = true;
3400  TrainController->TTEditPanelVisible = true; //added at v2.6.0 for two location message
3401  ShowHideTTButton->Hint = "Hide the timetable editor to see the railway Shift H";
3403  SetLevel1Mode(124);
3404  }
3405  }
3406  catch(const Exception &e)
3407  {
3408  ErrorLog(139, e.Message);
3409  }
3410 }
3411 // ---------------------------------------------------------------------------
3412 
3413 void __fastcall TInterface::NextTTEntryButtonClick(TObject *Sender)
3414 {
3415  try
3416  {
3417  TrainController->LogEvent("NextTTEntryButtonClick");
3418  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NextTTEntryButtonClick");
3419  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3420  {
3421  Utilities->CallLogPop(1683);
3422  return;
3423  }
3424  if(TTCurrentEntryPtr < (TimetableEditVector.end() - 1))
3426  TTEntryChangedFlag = false;
3427  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3428  // position changing in AllEntriesTTListBox
3430  SetLevel1Mode(85);
3431  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3432  {
3434  }
3435  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3436  {
3437  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3438  }
3439  else
3440  {
3441  AllEntriesTTListBox->TopIndex = TopPos;
3442  }
3443  Utilities->CallLogPop(1605);
3444  }
3445  catch(const Exception &e)
3446  {
3447  ErrorLog(50, e.Message);
3448  }
3449 }
3450 
3451 // ---------------------------------------------------------------------------
3452 void __fastcall TInterface::PreviousTTEntryButtonClick(TObject *Sender)
3453 {
3454  try
3455  {
3456  TrainController->LogEvent("PreviousTTEntryButtonClick");
3457  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PreviousTTEntryButtonClick");
3458  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3459  {
3460  Utilities->CallLogPop(1684);
3461  return;
3462  }
3465  TTEntryChangedFlag = false;
3466  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3467  // position changing in AllEntriesTTListBox
3469  SetLevel1Mode(86);
3470  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3471  {
3473  }
3474  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3475  {
3476  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3477  }
3478  else
3479  {
3480  AllEntriesTTListBox->TopIndex = TopPos;
3481  }
3482  Utilities->CallLogPop(1607);
3483  }
3484  catch(const Exception &e)
3485  {
3486  ErrorLog(51, e.Message);
3487  }
3488 }
3489 
3490 // ---------------------------------------------------------------------------
3491 void __fastcall TInterface::NewTTEntryButtonClick(TObject *Sender)
3492 {
3493  try
3494  {
3495  TrainController->LogEvent("NewTTEntryButtonClick");
3496  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewTTEntryButtonClick");
3497  OneEntryTimetableMemo->Clear();
3498  OneEntryTimetableMemo->SetFocus();
3501  SetLevel1Mode(103);
3502  Utilities->CallLogPop(1615);
3503  }
3504  catch(const Exception &e)
3505  {
3506  ErrorLog(52, e.Message);
3507  }
3508 }
3509 // ---------------------------------------------------------------------------
3510 
3511 void __fastcall TInterface::AddMinsButtonClick(TObject *Sender)
3512 {
3513  try
3514  {
3515  TrainController->LogEvent("AddMinsButtonClick");
3516  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddMinsButtonClick");
3517  bool ValidFlag = true;
3518  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3519  {
3520  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3521  {
3522  ValidFlag = false;
3523  break;
3524  }
3525  }
3526  if(ValidFlag)
3527  {
3528  if(AddSubMinsBox->Text.ToInt() == 0)
3529  ValidFlag = false;
3530  }
3531  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3532  {
3533  Utilities->CallLogPop(1649);
3534  return;
3535  }
3536  TDateTime DummyTime;
3537  int AddMins = AddSubMinsBox->Text.ToInt();
3538  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3539  {
3540  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3541  {
3542  if(TrainController->CheckTimeValidity(25, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3543  {
3544  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3545  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3546  Mins += AddMins;
3547  while(Mins >= 60)
3548  {
3549  Mins -= 60;
3550  Hrs++;
3551  }
3552  if(Hrs > 95)
3553  {
3554  ShowMessage("One or more times excessive, not permitted to exceed 95 hours");
3555  Utilities->CallLogPop(1650);
3556  return;
3557  }
3558  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3559  if(Mins < 10)
3560  MinsStr = "0" + MinsStr;
3561  if(Hrs < 10)
3562  HrsStr = "0" + HrsStr;
3563  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3564  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3565  NewString += HrsStr + ':' + MinsStr;
3566  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3567  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3568  }
3569  }
3570  }
3571 
3572  OneEntryTimetableMemo->HideSelection = true;
3573  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3574  OneEntryTimetableMemo->SelLength = 0;
3575  TimetableValidFlag = false;
3576  TimetableChangedFlag = true;
3577  TTEntryChangedFlag = true;
3579  SetLevel1Mode(91);
3580  Utilities->CallLogPop(1617);
3581  }
3582  catch(const Exception &e)
3583  {
3584  ErrorLog(54, e.Message);
3585  }
3586 }
3587 // ---------------------------------------------------------------------------
3588 
3589 void __fastcall TInterface::SubMinsButtonClick(TObject *Sender)
3590 {
3591  try
3592  {
3593  TrainController->LogEvent("SubMinsButtonClick");
3594  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SubMinsButtonClick");
3595  bool ValidFlag = true;
3596  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3597  {
3598  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3599  {
3600  ValidFlag = false;
3601  break;
3602  }
3603  }
3604  if(ValidFlag)
3605  {
3606  if(AddSubMinsBox->Text.ToInt() == 0)
3607  ValidFlag = false;
3608  }
3609  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3610  {
3611  Utilities->CallLogPop(1659);
3612  return;
3613  }
3614  TDateTime DummyTime;
3615  int SubMins = AddSubMinsBox->Text.ToInt();
3616  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3617  {
3618  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3619  {
3620  if(TrainController->CheckTimeValidity(28, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3621  {
3622  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3623  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3624  Mins -= SubMins;
3625  while(Mins < 0)
3626  {
3627  Mins += 60;
3628  Hrs--;
3629  }
3630  if(Hrs < 0)
3631  {
3632  ShowMessage("One or more times are now before 00:00, this is not permitted");
3633  Utilities->CallLogPop(1660);
3634  return;
3635  }
3636  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3637  if(Mins < 10)
3638  MinsStr = "0" + MinsStr;
3639  if(Hrs < 10)
3640  HrsStr = "0" + HrsStr;
3641  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3642  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3643  NewString += HrsStr + ':' + MinsStr;
3644  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3645  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3646  }
3647  }
3648  }
3649  OneEntryTimetableMemo->HideSelection = true;
3650  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3651  OneEntryTimetableMemo->SelLength = 0;
3652  TimetableValidFlag = false;
3653  TimetableChangedFlag = true;
3654  TTEntryChangedFlag = true;
3656  SetLevel1Mode(92);
3657  Utilities->CallLogPop(1618);
3658  }
3659  catch(const Exception &e)
3660  {
3661  ErrorLog(55, e.Message);
3662  }
3663 }
3664 // ---------------------------------------------------------------------------
3665 
3666 void __fastcall TInterface::CopyTTEntryButtonClick(TObject *Sender)
3667 {
3668  try
3669  {
3670  TrainController->LogEvent("CopyTTEntryButtonClick");
3671  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyTTEntryButtonClick");
3672  if(TTCurrentEntryPtr == 0)
3673  {
3674  Utilities->CallLogPop(1636);
3675  return;
3676  }
3678  CopiedEntryFlag = true;
3679  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3680  // position changing in AllEntriesTTListBox
3682  SetLevel1Mode(93);
3683  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3684  {
3686  }
3687  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3688  {
3689  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3690  }
3691  else
3692  {
3693  AllEntriesTTListBox->TopIndex = TopPos;
3694  }
3695  Utilities->CallLogPop(1619);
3696  }
3697  catch(const Exception &e)
3698  {
3699  ErrorLog(56, e.Message);
3700  }
3701 }
3702 // ---------------------------------------------------------------------------
3703 
3704 void __fastcall TInterface::CutTTEntryButtonClick(TObject *Sender)
3705 {
3706  try
3707  {
3708  TrainController->LogEvent("CutTTEntryButtonClick");
3709  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutTTEntryButtonClick");
3710  if(TTCurrentEntryPtr == 0) // || (*TTCurrentEntryPtr == ""))//safeguard
3711  {
3712  Utilities->CallLogPop(1674);
3713  return;
3714  }
3716  CopiedEntryFlag = true;
3717  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3718  // so use the position in the vector
3720 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3721 // pick up the start time if there is one
3722  TimetableChangedFlag = true;
3723  TimetableValidFlag = false;
3724  TTEntryChangedFlag = false;
3725  TEVPtr = 0;
3727  TTFirstServicePtr = 0;
3728  TTLastServicePtr = 0; // all set to null to begin with
3729  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3730  // position changing in AllEntriesTTListBox
3731  AllEntriesTTListBox->Clear();
3733  if(TimetableEditVector.empty())
3734  {
3736  SetLevel1Mode(109);
3737  Utilities->CallLogPop(1777);
3738  return;
3739  }
3740 
3741 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one //was 'after', changed after v2.4.3
3742 // but vector pointers unreliable after an erase, so use the position in the vector
3743  if(OldVectorPos == 0)
3744  {
3746  }
3747  else
3748  {
3749  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
3750  }
3751  if(TTCurrentEntryPtr == 0)
3752  {
3753  OneEntryTimetableMemo->Clear();
3754  }
3756  SetLevel1Mode(115);
3757  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3758  {
3760  }
3761  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3762  {
3763  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3764  }
3765  else
3766  {
3767  AllEntriesTTListBox->TopIndex = TopPos;
3768  }
3769  Utilities->CallLogPop(1676);
3770  }
3771  catch(const Exception &e)
3772  {
3773  ErrorLog(111, e.Message);
3774  }
3775 }
3776 
3777 // ---------------------------------------------------------------------------
3778 void __fastcall TInterface::PasteTTEntryButtonClick(TObject *Sender)
3779 {
3780  try
3781  {
3782  TrainController->LogEvent("PasteTTEntryButtonClick");
3783  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteTTEntryButtonClick");
3784  if(TTCurrentEntryPtr == 0) // || (CopiedEntryStr == "")) allow blank copies
3785  {
3786  Utilities->CallLogPop(1637);
3787  return;
3788  }
3789  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3790  TimetableEditVector.insert(TTCurrentEntryPtr + 1, CopiedEntryStr); // inserts before the indicated pointer position, i.e. immediately
3791  // after the current Entry - may be at the end
3792  TimetableChangedFlag = true;
3793  TimetableValidFlag = false;
3794  TTEntryChangedFlag = false;
3795  TEVPtr = 0;
3797  TTFirstServicePtr = 0;
3798  TTLastServicePtr = 0; // all set to null to begin with
3799  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3800  // position changing in AllEntriesTTListBox
3801  AllEntriesTTListBox->Clear();
3803  if(TimetableEditVector.empty())
3804  {
3806  SetLevel1Mode(110);
3807  Utilities->CallLogPop(1778);
3808  return;
3809  }
3810 // restore TTCurrentEntryPtr
3811  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3812  TTCurrentEntryPtr++; // advance the pointer to the pasted entry
3813 // CopiedEntryStr = "";//revert to null - no, allow multiple copies
3815  SetLevel1Mode(94);
3816  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3817  {
3819  }
3820  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3821  {
3822  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3823  }
3824  else
3825  {
3826  AllEntriesTTListBox->TopIndex = TopPos;
3827  }
3828  Utilities->CallLogPop(1620);
3829  }
3830  catch(const Exception &e)
3831  {
3832  ErrorLog(57, e.Message);
3833  }
3834 }
3835 // ---------------------------------------------------------------------------
3836 
3837 void __fastcall TInterface::DeleteTTEntryButtonClick(TObject *Sender)
3838 {
3839  try
3840  {
3841  TrainController->LogEvent("DeleteTTEntryButtonClick");
3842  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteTTEntryButtonClick");
3843  if(TTCurrentEntryPtr == 0)
3844  {
3845  Utilities->CallLogPop(1645);
3846  return;
3847  }
3848  UnicodeString MessageStr = "Are you sure this entry should be deleted?";
3849  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
3850  if(button == IDNO)
3851  {
3852  Utilities->CallLogPop(1663);
3853  return;
3854  }
3855  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3856  // so use the position in the vector
3858 
3859 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3860 // pick up the start time if there is one
3861  TimetableChangedFlag = true;
3862  TimetableValidFlag = false;
3863  TTEntryChangedFlag = false;
3864  TEVPtr = 0;
3866  TTFirstServicePtr = 0;
3867  TTLastServicePtr = 0; // all set to null to begin with
3868  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3869  // position changing in AllEntriesTTListBox
3870  AllEntriesTTListBox->Clear();
3872  if(TimetableEditVector.empty())
3873  {
3875  SetLevel1Mode(111);
3876  Utilities->CallLogPop(1779);
3877  return;
3878  }
3879 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one
3880 // but vector pointers unreliable after an erase, so use the position in the vector
3881  if(OldVectorPos == 0)
3882  {
3884  }
3885  else
3886  {
3887  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
3888  }
3889  if(TTCurrentEntryPtr == 0)
3890  {
3891  OneEntryTimetableMemo->Clear();
3892  }
3894  SetLevel1Mode(95);
3895  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3896  {
3898  }
3899  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3900  {
3901  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3902  }
3903  else
3904  {
3905  AllEntriesTTListBox->TopIndex = TopPos;
3906  }
3907  Utilities->CallLogPop(1621);
3908  }
3909  catch(const Exception &e)
3910  {
3911  ErrorLog(58, e.Message);
3912  }
3913 }
3914 // ---------------------------------------------------------------------------
3915 
3916 void __fastcall TInterface::SaveTTEntryButtonClick(TObject *Sender)
3917 {
3918  try
3919  {
3920  TrainController->LogEvent("SaveTTEntryButtonClick");
3921  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTEntryButtonClick");
3922 /* allow blank lines to be saved
3923  AnsiString ContentStr = OneEntryTimetableMemo->Text;
3924  if((ContentStr == "\r\n") || (ContentStr == "\n") || (ContentStr == ""))
3925  {
3926  Utilities->CallLogPop(1679);
3927  return;
3928  }
3929 */
3930  AnsiString TempStr = "";
3931  bool ActiveLine = false;
3932  if(TTCurrentEntryPtr > 0)
3933  {
3934  if(*TTCurrentEntryPtr != "")
3935  {
3937  {
3938  ActiveLine = true;
3939  // need to add commas after each line in OneEntryTimetableMemo exept the last, where have '\0'
3940  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3941  {
3942  for(int y = 1; y <= OneEntryTimetableMemo->Lines->Strings[x].Length(); y++)
3943  {
3944  TempStr += OneEntryTimetableMemo->Lines->Strings[x][y];
3945  }
3946  if(x < (OneEntryTimetableMemo->Lines->Count - 1))
3947  {
3948  TempStr += ',';
3949  }
3950  // No need to add a '\n' as a '\0' is added automatically as a string delimiter. If add '\n' then it is treated as a blank line and
3951  // ends the timetable
3952  }
3953  // strip any excess commas from the end
3954  if(TempStr != "")
3955  {
3956  while(TempStr[TempStr.Length()] == ',')
3957  {
3958  TempStr = TempStr.SubString(1, TempStr.Length() - 1);
3959  if(TempStr == "")
3960  break;
3961  }
3962  }
3963  }
3964  }
3965  }
3966  if(!ActiveLine)
3967  {
3968  TempStr = OneEntryTimetableMemo->Text; // Note that if the entry was intended as a service but goes in as plain text because
3969  // the service & entry pointers aren't yet set, then CRLFs will be converted to commas in
3970  // CompileAllEntriesMemoAndSetPointers if it appears after the start time
3971  // and before a blank line or end of file, so the syntax check will work OK
3972  }
3973  if(AZOrderButton->Caption == AnsiString("Original Order"))
3974  {
3976  }
3977  TimetableValidFlag = false;
3978  TimetableChangedFlag = true;
3979  TTEntryChangedFlag = false;
3980  int TopPos;
3981  if(TTCurrentEntryPtr == 0)
3982  {
3984  }
3986  {
3987  (*TTCurrentEntryPtr) = TempStr;
3988  // need to reset the AllEntriesTTListBox in case the headcode has changed
3989  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3990  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3991  // position changing in AllEntriesTTListBox
3992  AllEntriesTTListBox->Clear();
3994  if(TimetableEditVector.empty())
3995  {
3997  SetLevel1Mode(112);
3998  Utilities->CallLogPop(1780);
3999  return;
4000  }
4001  // restore TTCurrentEntryPtr
4002  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4003  }
4004  else
4005  {
4006  NewEntryInPreparationFlag = false;
4007  if(TTCurrentEntryPtr != 0)
4008  {
4009  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
4010  TimetableEditVector.insert(TTCurrentEntryPtr + 1, TempStr); // inserts before the indicated pointer position, which may be at the end
4011  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4013  }
4014  else
4015  {
4016  TimetableEditVector.insert(TimetableEditVector.end(), TempStr); // inserts before the indicated pointer position
4018  }
4019  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the current position
4020  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4021  // position changing in AllEntriesTTListBox
4022  AllEntriesTTListBox->Clear();
4024  if(TimetableEditVector.empty())
4025  {
4027  SetLevel1Mode(113);
4028  Utilities->CallLogPop(1781);
4029  return;
4030  }
4031 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4032  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4033  {
4035  }
4036  else
4037  {
4038  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4039  }
4040  }
4042  SetLevel1Mode(96);
4043  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4044  {
4046  }
4047  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4048  {
4049  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4050  }
4051  else
4052  {
4053  AllEntriesTTListBox->TopIndex = TopPos;
4054  }
4055  Utilities->CallLogPop(1622);
4056  }
4057  catch(const Exception &e)
4058  {
4059  ErrorLog(59, e.Message);
4060  }
4061 }
4062 // ---------------------------------------------------------------------------
4063 
4064 void __fastcall TInterface::SaveTTButtonClick(TObject *Sender)
4065 {
4066  try
4067  {
4068  TrainController->LogEvent("SaveTTButtonClick");
4069  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTButtonClick");
4070  if(TimetableEditVector.empty())
4071  {
4072  ShowMessage("Timetable is empty, can't save an empty timetable");
4073  Utilities->CallLogPop(1685);
4074  return;
4075  }
4076  std::ofstream TTBLFile;
4077  if(CreateEditTTFileName != "")
4078  {
4079  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4080  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4081  }
4082  else
4083  {
4084  if(SaveTTDialog->Execute())
4085  {
4086  if(SaveTTDialog->InitialDir != TPath::GetDirectoryName(SaveTTDialog->FileName))//new at v2.6.0 to retain a new directory
4087  {
4088  TimetableDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4089  SaveTTDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4090  }
4091  CreateEditTTFileName = AnsiString(SaveTTDialog->FileName);
4092  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
4093  {
4094  if(CreateEditTTFileName[x] == '\\')
4095  {
4096  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4097  break;
4098  }
4099  }
4100  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4101  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4102  }
4103  else //cancelled dialog
4104  {
4106  SetLevel1Mode(137);
4107  Utilities->CallLogPop(2205);
4108  return;
4109  }
4110  }
4111  if(TTBLFile.is_open())
4112  {
4113  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4114  {
4115  TTBLFile << (*TEVPtr).c_str() << '\0';
4116  }
4117  TimetableChangedFlag = false;
4118  TTBLFile.close();
4119  }
4120  else
4121  {
4122  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4123  }
4125  SetLevel1Mode(97);
4126  Utilities->CallLogPop(1623);
4127  }
4128  catch(const Exception &e)
4129  {
4130  ErrorLog(60, e.Message);
4131  }
4132 }
4133 // ---------------------------------------------------------------------------
4134 
4135 void __fastcall TInterface::SaveTTAsButtonClick(TObject *Sender)
4136 {
4137  try
4138  {
4139  TrainController->LogEvent("SaveTTAsButtonClick");
4140  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTAsButtonClick");
4141  if(TimetableEditVector.empty())
4142  {
4143  ShowMessage("Timetable is empty, can't save an empty timetable");
4144  Utilities->CallLogPop(1686);
4145  return;
4146  }
4147  std::ofstream TTBLFile;
4148  if(SaveTTDialog->Execute())
4149  {
4150  if(SaveTTDialog->InitialDir != TPath::GetDirectoryName(SaveTTDialog->FileName))//new at v2.6.0 to retain a new directory
4151  {
4152  TimetableDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4153  SaveTTDialog->InitialDir = TPath::GetDirectoryName(SaveTTDialog->FileName);
4154  }
4155  CreateEditTTFileName = SaveTTDialog->FileName;
4156  for(int x = SaveTTDialog->FileName.Length(); x > 0; x--)
4157  {
4158  if(SaveTTDialog->FileName[x] == '\\')
4159  {
4160  CreateEditTTTitle = SaveTTDialog->FileName.SubString(x + 1, SaveTTDialog->FileName.Length() - x - 4);
4161  break;
4162  }
4163  }
4164  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4165  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4166  }
4167  else //cancelled dialog
4168  {
4170  SetLevel1Mode(138);
4171  Utilities->CallLogPop(2206);
4172  return;
4173  }
4174  if(TTBLFile.is_open())
4175  {
4176  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4177  {
4178  TTBLFile << (*TEVPtr).c_str() << '\0';
4179  }
4180  TimetableChangedFlag = false;
4181  TTBLFile.close();
4182  }
4183  else
4184  {
4185  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4186  }
4188  SetLevel1Mode(117);
4189  Utilities->CallLogPop(1667);
4190  }
4191  catch(const Exception &e)
4192  {
4193  ErrorLog(108, e.Message);
4194  }
4195 }
4196 // ---------------------------------------------------------------------------
4197 
4198 void __fastcall TInterface::TTServiceSyntaxCheckButtonClick(TObject *Sender)
4199 {
4200  try
4201  {
4202  TrainController->LogEvent("TTServiceSyntaxCheckButtonClick");
4203  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTServiceSyntaxCheckButtonClick");
4204  int Count = 1; // anything > 0 OK as if 0 still seeking a start time
4205  bool EndOfFile = false;
4206  bool FinalCallFalse = false;
4207  bool GiveMessagesTrue = true;
4208  bool CheckLocationsExistInRailway = false;
4209  if(RlyFile)
4210  CheckLocationsExistInRailway = true;
4211 // TrainController->AnyHeadCodeValid = true; //don't fail here because of an unrestricted headcode, if no good will find when validate (dropped at v0.6b)
4212  if(TrainController->ProcessOneTimetableLine(2, Count, *TTCurrentEntryPtr, EndOfFile, FinalCallFalse, GiveMessagesTrue, CheckLocationsExistInRailway))
4213  // return true for success
4214  {
4215  ShowMessage(
4216  "The basic syntax seems OK but this check is very limited. Other aspects can only be checked by validating the whole timetable with the appropriate railway (.rly) loaded");
4217  }
4219  SetLevel1Mode(98);
4220  Utilities->CallLogPop(1624);
4221  }
4222  catch(const Exception &e)
4223  {
4224  ErrorLog(61, e.Message);
4225  }
4226 }
4227 // ---------------------------------------------------------------------------
4228 
4229 void __fastcall TInterface::ValidateTimetableButtonClick(TObject *Sender)
4230 {
4231  try
4232  {
4233  TrainController->LogEvent("ValidateTimetableButtonClick");
4234  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ValidateTimetableButtonClick");
4235  // reset all message flags, stops them being given twice new at v2.4.0
4236  TrainController->SSHigh = false;
4237  TrainController->MRSHigh = false;
4238  TrainController->MRSLow = false;
4239  TrainController->MassHigh = false;
4240  TrainController->BFHigh = false;
4241  TrainController->BFLow = false;
4242  TrainController->PwrHigh = false;
4243  TrainController->SigSHigh = false;
4244  TrainController->SigSLow = false;
4245  if(CreateEditTTFileName == "")
4246  {
4247  Utilities->CallLogPop(1664);
4248  return;
4249  }
4250  bool CheckLocationsExistInRailwayTrue = true;
4251  if(TrainController->TimetableIntegrityCheck(2, CreateEditTTFileName.c_str(), true, CheckLocationsExistInRailwayTrue)) // messages = true
4252  {
4253  Screen->Cursor = TCursor(-11); // Hourglass;
4254  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4255  if(TTBLFile.is_open())
4256  {
4257  if(BuildTrainDataVectorForValidateFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue)) // messages = true
4258  {
4259  ShowMessage("Timetable integrity OK");
4260  TimetableValidFlag = true;
4261 // TrainController->TrainDataVector.clear(); keep this so can export a formatted tt
4262  };
4263  }
4264  else
4265  {
4266  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
4267  }
4268  Screen->Cursor = TCursor(-2); // Arrow
4269  } // if(TimetableIntegrityCheck
4270  else
4271  {
4272 // ShowMessage("Timetable preliminary integrity check failed"); dropped in v2.4.0 as messages given in all called functions
4273  }
4275  SetLevel1Mode(99);
4276  Utilities->CallLogPop(1625);
4277  }
4278  catch(const Exception &e)
4279  {
4280  ErrorLog(62, e.Message);
4281  }
4282 }
4283 
4284 // ---------------------------------------------------------------------------
4285 void __fastcall TInterface::MoveTTEntryUpButtonClick(TObject *Sender)
4286 {
4287  try
4288  {
4289  TrainController->LogEvent("MoveTTEntryUpButtonClick");
4290  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryUpButtonClick");
4291  if(TTCurrentEntryPtr == 0)
4292  {
4293  Utilities->CallLogPop(1634);
4294  return;
4295  }
4296  if(TTCurrentEntryPtr < (TimetableEditVector.begin() + 1)) // shouldn't reach here but return if do
4297  {
4298  Utilities->CallLogPop(1632);
4299  return;
4300  }
4301  TEVPtr = TTCurrentEntryPtr - 1; // find earlier Entry
4302  AnsiString TempStr = *TEVPtr;
4304  *TTCurrentEntryPtr = TempStr;
4306  TimetableChangedFlag = true;
4307  TimetableValidFlag = false;
4308 
4309 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4310  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4311  // position changing in AllEntriesTTListBox
4312  AllEntriesTTListBox->Clear();
4313  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4315 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4316  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4317  {
4319  }
4320  else
4321  {
4322  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4323  }
4325  SetLevel1Mode(100);
4326  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4327  {
4329  }
4330  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4331  {
4332  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4333  }
4334  else
4335  {
4336  AllEntriesTTListBox->TopIndex = TopPos;
4337  }
4338  Utilities->CallLogPop(1626);
4339  }
4340  catch(const Exception &e)
4341  {
4342  ErrorLog(63, e.Message);
4343  }
4344 }
4345 // ---------------------------------------------------------------------------
4346 
4347 void __fastcall TInterface::MoveTTEntryDownButtonClick(TObject *Sender)
4348 {
4349  try
4350  {
4351  TrainController->LogEvent("MoveTTEntryDownButtonClick");
4352  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryDownButtonClick");
4353  if(TTCurrentEntryPtr == 0)
4354  {
4355  Utilities->CallLogPop(1635);
4356  return;
4357  }
4358  if(TTCurrentEntryPtr >= (TimetableEditVector.end() - 1)) // shouldn't reach here but return if do
4359  {
4360  Utilities->CallLogPop(1678);
4361  return;
4362  }
4363  TEVPtr = TTCurrentEntryPtr + 1; // find later Entry
4364  AnsiString TempStr = *TEVPtr;
4366  *TTCurrentEntryPtr = TempStr;
4368  TimetableChangedFlag = true;
4369  TimetableValidFlag = false;
4370 
4371 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4372  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4373  // position changing in AllEntriesTTListBox
4374  AllEntriesTTListBox->Clear();
4375  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4377 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4378  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4379  {
4381  }
4382  else
4383  {
4384  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4385  }
4387  SetLevel1Mode(101);
4388  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4389  {
4391  }
4392  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4393  {
4394  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4395  }
4396  else
4397  {
4398  AllEntriesTTListBox->TopIndex = TopPos;
4399  }
4400  Utilities->CallLogPop(1627);
4401  }
4402  catch(const Exception &e)
4403  {
4404  ErrorLog(64, e.Message);
4405  }
4406 }
4407 
4408 // ---------------------------------------------------------------------------
4409 void __fastcall TInterface::CancelTTEntryButtonClick(TObject *Sender)
4410 {
4411  try
4412  {
4413  TrainController->LogEvent("CancelTTActionButtonClick");
4414  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelTTActionButtonClick");
4415  TTEntryChangedFlag = false;
4417  {
4418  NewEntryInPreparationFlag = false;
4419  OneEntryTimetableMemo->Clear();
4420  }
4421  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4422  // position changing in AllEntriesTTListBox
4424  SetLevel1Mode(102);
4425  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4426  {
4428  }
4429  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4430  {
4431  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4432  }
4433  else
4434  {
4435  AllEntriesTTListBox->TopIndex = TopPos;
4436  }
4437  Utilities->CallLogPop(1630);
4438  }
4439  catch(const Exception &e)
4440  {
4441  ErrorLog(102, e.Message);
4442  }
4443 }
4444 
4445 // ---------------------------------------------------------------------------
4446 void __fastcall TInterface::RestoreTTButtonClick(TObject *Sender)
4447 {
4448  try
4449  {
4450  TrainController->LogEvent("RestoreTTButtonClick");
4451  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreTTButtonClick");
4453  {
4454  UnicodeString MessageStr = "All changes to the timetable will be lost - proceed?";
4455  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4456  if(button == IDNO)
4457  {
4458  Utilities->CallLogPop(1651);
4459  return;
4460  }
4461  }
4462 
4463  // repeat from EditTimetableMenuItemClick, but no need to check for non-ascii characters
4464  // open in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
4465  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4466  if(TTBLFile.is_open())
4467  {
4468  TimetableChangedFlag = false;
4469  TimetableValidFlag = false;
4470  TTEntryChangedFlag = false;
4471  NewEntryInPreparationFlag = false;
4472  CopiedEntryFlag = false;
4473  CopiedEntryStr = "";
4474  TimetableEditVector.clear();
4475  OneEntryTimetableMemo->Clear();
4476  AllEntriesTTListBox->Clear();
4477  TTStartTimeBox->Text = "";
4478  AddSubMinsBox->Text = "";
4479  TEVPtr = 0;
4481  TTFirstServicePtr = 0;
4482  TTLastServicePtr = 0; // all set to null to begin with
4483  char *TimetableEntryString = new char[10000];
4484  while(true)
4485  {
4486  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
4487  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
4488  { // may still have eof even if read a line, and
4489  // if so need to process it
4490  break;
4491  }
4492  AnsiString OneLine(TimetableEntryString);
4493  TimetableEditVector.push_back(OneLine);
4494  }
4495  TTBLFile.close();
4496  delete TimetableEntryString;
4497  // here with TimetableEditVector compiled
4498  }
4499  else
4500  {
4501  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
4502  Utilities->CallLogPop(1655);
4503  return;
4504  }
4505 
4507  if(TimetableEditVector.empty())
4508  {
4510  SetLevel1Mode(114);
4511  Utilities->CallLogPop(1782);
4512  return;
4513  }
4514 // all now set where can be
4516 // end of repeat from EditTimetableMenuItemClick
4517 
4519  SetLevel1Mode(104);
4520  Utilities->CallLogPop(1652);
4521  }
4522  catch(const Exception &e)
4523  {
4524  ErrorLog(104, e.Message);
4525  }
4526 }
4527 
4528 // ---------------------------------------------------------------------------
4529 void __fastcall TInterface::ExportTTButtonClick(TObject *Sender)
4530 {
4531  try
4532  {
4533  TrainController->LogEvent("ExportTTButtonClick");
4534  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTButtonClick");
4535  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
4536  {
4537  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
4538  Utilities->CallLogPop(1698);
4539  return;
4540  }
4541 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
4542 // the message instead, but reset here afterwards
4543  AnsiString TTTitle;
4545  {
4546  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
4547  {
4548  if(CreateEditTTFileName[x] == '\\')
4549  {
4550  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4551  break;
4552  }
4553  }
4555  }
4556  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
4558  SetLevel1Mode(116);
4559  Utilities->CallLogPop(1662);
4560  }
4561  catch(const Exception &e)
4562  {
4563  ErrorLog(107, e.Message);
4564  }
4565 }
4566 
4567 // ---------------------------------------------------------------------------
4568 void __fastcall TInterface::TTTextButtonClick(TObject *Sender)
4569 {
4570  try
4571  {
4572  TrainController->LogEvent("TTTextButtonClick");
4573  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTTextButtonClick");
4574 /*
4575  if(TTStartTimePtr == 0)
4576  {
4577  OneEntryTimetableMemo->Clear();
4578  TTStartTimeBox->SetFocus();
4579  Utilities->CallLogPop(1673);
4580  return;
4581  }
4582 */
4583  int SelPos = OneEntryTimetableMemo->SelStart;
4584  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4585  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4586  OneEntryTimetableMemo->Text = FirstPart + ((TButton*)Sender)->Caption + LastPart;
4587  OneEntryTimetableMemo->SelStart = SelPos + ((TButton*)Sender)->Caption.Length();
4588  TTEntryChangedFlag = true;
4589  OneEntryTimetableMemo->SetFocus();
4591  SetLevel1Mode(119);
4592  Utilities->CallLogPop(1672);
4593  }
4594  catch(const Exception &e)
4595  {
4596  ErrorLog(110, e.Message);
4597  }
4598 }
4599 
4600 // ---------------------------------------------------------------------------
4601 void __fastcall TInterface::ExitTTModeButtonClick(TObject *Sender)
4602 {
4603  try
4604  {
4605  TrainController->LogEvent("ExitTTCreateEditButtonClick");
4606  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTTCreateEditButtonClick");
4608  {
4609  UnicodeString MessageStr = "The timetable has changed.\n\nAre you sure you want to exit without saving it?";
4610  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4611  if(button == IDNO)
4612  {
4613  Utilities->CallLogPop(1603);
4614  return;
4615  }
4616  }
4617  TimetableChangedFlag = false;
4618  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
4619  // added for Beta v0.2b
4620  CreateEditTTTitle = ""; // as above
4621  ConflictPanel->Visible = false;
4622  Level1Mode = BaseMode;
4623  SetLevel1Mode(84);
4624  Utilities->CallLogPop(1606);
4625  }
4626  catch(const Exception &e)
4627  {
4628  ErrorLog(49, e.Message);
4629  }
4630 }
4631 
4632 // ---------------------------------------------------------------------------
4633 void __fastcall TInterface::LocationNameComboBoxClick(TObject *Sender)
4634 {
4635  try
4636  {
4637  TrainController->LogEvent("LocationNameComboBoxClick");
4638  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxClick");
4639  if(TTStartTimePtr != 0)
4640  {
4641  LocationNameComboBox->SelectAll();
4642  int SelPos = OneEntryTimetableMemo->SelStart;
4643  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4644  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4645  OneEntryTimetableMemo->Text = FirstPart + LocationNameComboBox->SelText + LastPart;
4646  OneEntryTimetableMemo->SelStart = SelPos + LocationNameComboBox->SelText.Length();
4647  TTEntryChangedFlag = true;
4648  OneEntryTimetableMemo->SetFocus();
4650  SetLevel1Mode(118);
4651  }
4652  Utilities->CallLogPop(1669);
4653  }
4654  catch(const Exception &e)
4655  {
4656  ErrorLog(109, e.Message);
4657  }
4658 }
4659 
4660 // ---------------------------------------------------------------------------
4661 void __fastcall TInterface::OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4662 {
4663  try
4664  {
4665 // TrainController->LogEvent("OneEntryTimetableMemoKeyUp"); drop this - too many entries
4666  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OneEntryTimetableMemoKeyUp");
4668  {
4669  Utilities->CallLogPop(1716);
4670  return;
4671  }
4672  TimetableChangedFlag = true;
4673  TTEntryChangedFlag = true;
4674  TimetableValidFlag = false;
4676  SetLevel1Mode(127);
4677  Utilities->CallLogPop(1629);
4678  }
4679  catch(const Exception &e)
4680  {
4681  ErrorLog(66, e.Message);
4682  }
4683 }
4684 
4685 // ---------------------------------------------------------------------------
4686 void __fastcall TInterface::AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4687 {
4688 // forces a recheck for whether addmins/submins buttons should be enabled
4689  try
4690  {
4691  TrainController->LogEvent("AddSubMinsBoxKeyUp");
4692  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddSubMinsBoxKeyUp");
4694  SetLevel1Mode(108);
4695  Utilities->CallLogPop(1658);
4696  }
4697  catch(const Exception &e)
4698  {
4699  ErrorLog(106, e.Message);
4700  }
4701 }
4702 
4703 // ---------------------------------------------------------------------------
4704 void __fastcall TInterface::LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4705 {
4706  try
4707  {
4708  TrainController->LogEvent("LocationNameComboBoxKeyUp");
4709  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxKeyUp");
4710  if(!Track->LocationNameMultiMap.empty())
4711  {
4712  LocationNameComboBox->Text = "Location names";
4713  }
4714  else
4715  {
4716  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
4717  }
4718  Utilities->CallLogPop(1677);
4719  }
4720  catch(const Exception &e)
4721  {
4722  ErrorLog(112, e.Message);
4723  }
4724 }
4725 
4726 // ---------------------------------------------------------------------------
4727 
4728 void __fastcall TInterface::AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button,
4729  TShiftState Shift, int X, int Y)
4730 {
4731 // Select the item pointed to unless a 'save entry' is pending in which case ignore
4732  try
4733  {
4734  TrainController->LogEvent("AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4735  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4736  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
4737  {
4738  Utilities->CallLogPop(1687);
4739  return;
4740  }
4741  if(TTEntryChangedFlag || NewEntryInPreparationFlag) // if a save/cancel pending don't permit anything else
4742  {
4743  Utilities->CallLogPop(1688);
4744  return;
4745  }
4746  // find item required - 13 pixels per line of text
4747  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4748  // position changing in AllEntriesTTListBox
4749  if((TopPos + (Y / 13)) >= AllEntriesTTListBox->Items->Count)
4750  {
4752  }
4753  else
4754  {
4755  TTCurrentEntryPtr = TimetableEditVector.begin() + (Y / 13) + TopPos;
4756  }
4757  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4759 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4760  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4761  {
4763  }
4764  else
4765  {
4766  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4767  }
4769  SetLevel1Mode(120);
4770  AllEntriesTTListBox->TopIndex = TopPos; // reset it after SetLevel1Mode to prevent the scroll position changing
4771  Utilities->CallLogPop(1648);
4772  }
4773  catch(const Exception &e)
4774  {
4775  ErrorLog(103, e.Message);
4776  }
4777 }
4778 
4779 // ---------------------------------------------------------------------------
4780 
4781 void __fastcall TInterface::OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4782 {
4783 // Mouseup rather than Mousedown so shows floating label when over selected train
4784  try
4785  {
4786  TrainController->LogEvent("OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y) + "," + AnsiString(Button)); //button may be right or left
4787  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4788  if(Track->RouteFlashFlag || Track->PointFlashFlag) // no action
4789  {
4790  Utilities->CallLogPop(2087);
4791  return;
4792  }
4794  {
4795  Utilities->CallLogPop(2088);
4796  return;
4797  }
4798  int HPos, VPos, TrainID = -1, TrackVectorPosition = -1;
4799  if(!GetTrainIDOrContinuationPosition(0, X, Y, TrainID, TrackVectorPosition))
4800  {
4801  OAListBoxRightMouseButtonDown = false; //so resets when button over blank area
4802  Utilities->CallLogPop(2260);
4803  return;
4804  }
4805  if(Button == mbLeft) //added at v2.7.0 to keep right button for train information
4806  {
4807  HPos = (Track->TrackElementAt(926, TrackVectorPosition).HLoc * 16);
4808  VPos = (Track->TrackElementAt(927, TrackVectorPosition).VLoc * 16);
4809  // now want to set the offsets to display HPos & VPos in the centre of the screen
4810  Display->DisplayOffsetH = (HPos - MainScreen->Width / 2) / 16; // ScreenPosH = HPos - (DisplayOffsetH * 16)
4811  Display->DisplayOffsetV = (VPos - MainScreen->Height / 2) / 16;
4812  int ScreenPosH = HPos - (Display->DisplayOffsetH * 16);
4813  int ScreenPosV = VPos - (Display->DisplayOffsetV * 16);
4814  if(Display->ZoomOutFlag) // panel displays in either zoom mode
4815  {
4816  Display->ZoomOutFlag = false;
4818  }
4819  ClearandRebuildRailway(72); // if was zoomed out this displays the track because until ZoomOutFlag reset PlotOutput plots nothing
4820  TPoint MainScreenPoint(ScreenPosH + 8, ScreenPosV + 8); // new v2.2.0 add 8 to centre pointer in element
4821  TPoint CursPos = MainScreen->ClientToScreen(MainScreenPoint); // accurate funtion to convert from local to global co-ordinates
4822  Mouse->CursorPos = CursPos;
4823  }
4824  else //mbRight, reset OAListBoxRightMouseButtonDown
4825  {
4827  }
4828  Utilities->CallLogPop(2090);
4829  }
4830  catch(const Exception &e)
4831  {
4832  ErrorLog(200, e.Message);
4833  }
4834 }
4835 
4836 // ---------------------------------------------------------------------------
4837 
4838 void __fastcall TInterface::OAListBoxMouseDown(TObject *Sender, TMouseButton Button,
4839  TShiftState Shift, int X, int Y)
4840 {
4841  try
4842  {
4843  TrainController->LogEvent("OAListBoxMouseDown," + AnsiString(X) + "," + AnsiString(Y));
4844  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseDown");
4845  if(Button == mbRight)
4846  {
4848  }
4849  Utilities->CallLogPop(2264);
4850  }
4851  catch(const Exception &e)
4852  {
4853  ErrorLog(220, e.Message);
4854  }
4855 }
4856 
4857 //---------------------------------------------------------------------------
4858 
4859 bool TInterface::GetTrainIDOrContinuationPosition(int Caller, int X, int Y, int &TrainID, int &TrackVectorPosition)
4860 //returns true if value(s) valid
4861 {
4862  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetTrainIDOrContinuationPosition");
4864  // find item required - 13 pixels per line of text
4865  int TopPos = OAListBox->TopIndex;
4866  int OAIndex;
4867  if((TopPos + (Y / 13)) >= OAListBox->Items->Count) // if click beyond end of list ignore
4868  {
4869  Utilities->CallLogPop(2089);
4870  return false;
4871  }
4872  else
4873  {
4874  OACurrentEntryPtr = TrainController->OpTimeToActMultiMap.begin();
4875  std::advance(OACurrentEntryPtr, ((Y / 13) + TopPos));
4876  }
4877  int TrainIDorTVPos = OACurrentEntryPtr->second.second;
4878  if(TrainIDorTVPos >= 0) // running train, so value is the TrainID
4879  {
4880  if(TrainController->TrainExistsAtIdent(0, TrainIDorTVPos)) // added at v2.4.0 in case train removed but still in OA list as not updated yet
4881  // see LiWinDom error report on Discord 23/04/20. Also needed for click OAListBox before any trains show,
4882  // as notified by Rokas Serys by email on 16/05/20
4883  {
4884  TrainID = TrainIDorTVPos;
4885  TrackVectorPosition = TrainController->TrainVectorAtIdent(43, TrainIDorTVPos).LeadElement;
4886  }
4887  else
4888  {
4889  Utilities->CallLogPop(2155); // if not there then ignore
4890  return false;
4891  }
4892  }
4893  else // train to enter at a continuation, so value is -TVPos of continuation - 1
4894  {
4895  TrackVectorPosition = -(TrainIDorTVPos + 1);
4896  }
4897  Utilities->CallLogPop(2261);
4898  return true;
4899 }
4900 
4901 // ---------------------------------------------------------------------------
4902 
4904 {
4905  enum
4906  {
4907  PreStartTime, ActiveSegment, PostEnd} Segment;
4908  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CompileAllEntriesMemoAndSetPointers");
4909  AllEntriesTTListBox->Clear();
4910  TEVPtr = 0;
4911  TTStartTimePtr = 0;
4912  TTFirstServicePtr = 0;
4913  TTLastServicePtr = 0; // all set to null to begin with
4914  if(TimetableEditVector.empty())
4915  {
4916  TTCurrentEntryPtr = 0;
4917  Utilities->CallLogPop(1681);
4918  return;
4919  }
4920  Segment = PreStartTime;
4921  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4922  {
4923  if(Segment == PreStartTime) // looking for the start time
4924  {
4925  TDateTime TempTime; // dummy
4926  if(TrainController->CheckTimeValidity(33, *TEVPtr, TempTime))
4927  {
4928  TTStartTimePtr = TEVPtr; // TTStartTimeBox text set in TTHandler
4929  AllEntriesTTListBox->Items->Add("START " + (*TEVPtr).SubString(1, 5));
4930  Segment = ActiveSegment;
4931  continue;
4932  }
4933  else
4934  {
4935  if(*TEVPtr == "")
4936  {
4937  AllEntriesTTListBox->Items->Add("- Blank");
4938  }
4939  else
4940  {
4941  AnsiString CurrentStr = *TEVPtr;
4942  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
4943  {
4944  CurrentStr = CurrentStr.SubString(1, 10); // limit length for LH window
4945  for(int x = 1; x < CurrentStr.Length(); x++)
4946  {
4947  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
4948  {
4949  CurrentStr = CurrentStr.SubString(1, (x - 1));
4950  }
4951  }
4952  }
4953  AllEntriesTTListBox->Items->Add("- " + CurrentStr);
4954  }
4955  continue;
4956  }
4957  }
4958  if(Segment == ActiveSegment)
4959  {
4960  if(*TEVPtr != "")
4961  {
4962  if((*TEVPtr)[1] != '*')
4963  {
4965  ConvertCRLFsToCommas(0, *TEVPtr); // This needed because an entry intended as a service might have skipped the conversion in
4966  // SaveTTEntryButtonClick - see comment in that function
4967  if(TTFirstServicePtr == 0)
4968  {
4970  }
4972  }
4973  AnsiString Entry = *TEVPtr;
4974  if(Entry[1] == '*')
4975  Entry = "Comment";
4976  else
4977  {
4978  int SCPos = Entry.Pos(';'); // semicolon
4979  int CPos = Entry.Pos(','); // comma
4980  // 5 possibilities: no comma & no semicolon - just text - enter 1st 12 characters
4981  // both, comma before semicolon, i.e text on its own line, semicolon on next line - e.g. service headcode but no
4982  // description - enter the text up to the comma
4983  // both, semicolon before comma, normal - enter text up to the semicolon
4984  // comma & no semicolon, one or more lines of text without any semicolons - enter the text up to the comma
4985  // semicolon & no comma - enter text up to the semicolon
4986  if((CPos == 0) && (SCPos == 0))
4987  {
4988  Entry = Entry.SubString(1, 12);
4989  }
4990  else if((CPos > 0) && (SCPos > 0) && (CPos < SCPos))
4991  {
4992  Entry = Entry.SubString(1, CPos - 1);
4993  }
4994  else if((CPos > 0) && (SCPos > 0) && (CPos > SCPos))
4995  {
4996  Entry = Entry.SubString(1, SCPos - 1);
4997  }
4998  else if((CPos > 0) && (SCPos == 0))
4999  {
5000  Entry = Entry.SubString(1, CPos - 1);
5001  }
5002  else
5003  {
5004  Entry = Entry.SubString(1, SCPos - 1);
5005  }
5006  }
5007  AllEntriesTTListBox->Items->Add(Entry);
5008  continue;
5009  }
5010  else
5011  {
5012  Segment = PostEnd;
5013  AllEntriesTTListBox->Items->Add("END (Blank)");
5014  continue;
5015  }
5016  }
5017  if(Segment == PostEnd)
5018  {
5019  if(*TEVPtr == "")
5020  {
5021  AllEntriesTTListBox->Items->Add("+ Blank");
5022  }
5023  else
5024  {
5025  AnsiString CurrentStr = *TEVPtr;
5026  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5027  {
5028  CurrentStr = CurrentStr.SubString(1, 10);
5029  for(int x = 1; x < CurrentStr.Length(); x++)
5030  {
5031  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5032  {
5033  CurrentStr = CurrentStr.SubString(1, (x - 1));
5034  }
5035  }
5036  }
5037  AllEntriesTTListBox->Items->Add("+ " + CurrentStr);
5038  }
5039  continue;
5040  }
5041  }
5042  if(TTStartTimePtr == 0)
5043  {
5044  TTStartTimeBox->Text = "";
5045  }
5046  TTCurrentEntryPtr = TTLastServicePtr; // may well be reset outside this function but need to ensure that it has a valid value on exit, even if it's null
5047  Utilities->CallLogPop(1680);
5048 }
5049 // ---------------------------------------------------------------------------
5050 
5051 void __fastcall TInterface::AZOrderButtonClick(TObject *Sender)
5052 {
5053  try
5054  {
5055  if(TimetableEditVector.empty())
5056  {
5057  return; // should be able to access this if it is but keep in for safety
5058  }
5059  TrainController->LogEvent("AZOrderClick");
5060  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AZOrderClick");
5061  if(AZOrderButton->Caption == AnsiString("A-Z Order"))
5062  {
5063  TTEVPtr SortStart, SortEnd;
5064  UnicodeString MessageStr =
5065  "If you wish to preserve the original order don't make any changes whilst in alphabetical order.\n\nIn that case use alphabetical order to find the service required, click it to display it, then revert to the original order where the same service will be displayed and can be changed.";
5066  Application->MessageBox(MessageStr.c_str(), L"Please Note:", MB_OK | MB_ICONWARNING);
5069  SortStart = TimetableEditVector.begin(); // if no start time set sort from beginning
5070  if(TTFirstServicePtr != NULL)
5071  {
5072  SortStart = TTFirstServicePtr;
5073  }
5074  SortEnd = TimetableEditVector.end(); // if no last service set sort to end
5075  if(TTLastServicePtr != NULL)
5076  {
5077  SortEnd = TTLastServicePtr + 1;
5078  }
5079  std::sort(SortStart, SortEnd);
5081  bool CurrentEntryChanged = false;
5082  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
5083  {
5084  if(TTSelectedEntry == *x)
5085  {
5086  TTCurrentEntryPtr = x;
5087  CurrentEntryChanged = true;
5088  }
5089  }
5090  if(!CurrentEntryChanged)
5091  {
5093  }
5094  AZOrderButton->Caption = AnsiString("Original Order");
5095  AZOrderButton->Hint = AnsiString("Arrange services in original order Toggle with Shift+ Z");
5096  }
5097  else
5098  {
5100  {
5101  UnicodeString MessageStr =
5102  "Reverting to the original order will discard any changes made whilst in alphabetical order.\n\nTo preserve the changes click 'No', then save the timetable or use 'save as' if you wish to keep the original timetable.\n\nDo you wish to proceed?";
5103  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
5104  if(button == IDNO)
5105  {
5106  TimetableChangedFlag = true;
5107  TimetableValidFlag = false;
5109  SetLevel1Mode(135);
5110  Utilities->CallLogPop(2166);
5111  return;
5112  }
5113  }
5117  bool CurrentEntryChanged = false;
5118  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
5119  {
5120  if(TTSelectedEntry == *x)
5121  {
5122  TTCurrentEntryPtr = x;
5123  CurrentEntryChanged = true;
5124  }
5125  }
5126  if(!CurrentEntryChanged)
5127  {
5129  }
5130  AZOrderButton->Caption = AnsiString("A-Z Order");
5131  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
5132  }
5133  TimetableChangedFlag = true;
5134  TimetableValidFlag = false;
5137  SetLevel1Mode(136);
5138  Utilities->CallLogPop(2165);
5139  }
5140  catch(const Exception &e)
5141  {
5142  ErrorLog(211, e.Message);
5143  }
5144 }
5145 
5146 // ---------------------------------------------------------------------------
5147 
5148 void TInterface::ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
5149 {
5150  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertCRLFsToCommas," + ConvStr);
5151  AnsiString OutStr = "";
5152  int x = 1; // AnsiString arrays start at 1
5153 
5154  while(x < ConvStr.Length()) // skip the last character as looking for CRLF pairs, i.e. '\r' followed by '\n'
5155  {
5156  if((ConvStr[x] == '\r') && (ConvStr[x + 1] == '\n'))
5157  {
5158  OutStr += ',';
5159  x++;
5160  x++;
5161  }
5162  else
5163  {
5164  OutStr += ConvStr[x];
5165  x++;
5166  }
5167  }
5168  if(x == ConvStr.Length())
5169  OutStr += ConvStr[x]; // add the last character
5170 
5171 // strip any excess commas from the end
5172  if(OutStr != "")
5173  {
5174  while(OutStr[OutStr.Length()] == ',')
5175  {
5176  OutStr = OutStr.SubString(1, OutStr.Length() - 1);
5177  if(OutStr == "")
5178  break; // if consisted of just commas then without this would fail on range error when becomes a null string
5179  }
5180  }
5181  ConvStr = OutStr;
5182  if(ConvStr == "")
5183  ConvStr = ','; // don't return a null or will fail, OK to return a comma on its own as will be ignored during ProcessOneTimetableLine
5184  // when AllCommas will be true
5185  Utilities->CallLogPop(1846);
5186 }
5187 
5188 // ---------------------------------------------------------------------------
5189 
5191 {
5192 /* CreateEditTTFileName set if a TT file loaded (even if empty), the pointers TTStartTimePtr, TTFirstServicePtr, TTLastServicePtr provide
5193  relevant information - if null then not set. TTCurrentEntryPtr is set to the Entry to be displayed or null if there's no start time or no
5194  entries
5195 */
5196  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableHandler");
5197  PreviousTTEntryButton->Enabled = false;
5198  NextTTEntryButton->Enabled = false;
5199  AddMinsButton->Enabled = false;
5200  SubMinsButton->Enabled = false;
5201  CopyTTEntryButton->Enabled = false;
5202  CutTTEntryButton->Enabled = false;
5203  PasteTTEntryButton->Enabled = false;
5204  DeleteTTEntryButton->Enabled = false;
5205  SaveTTEntryButton->Enabled = false;
5206  SaveTTButton->Enabled = false;
5207  SaveTTAsButton->Enabled = false;
5208  ValidateTimetableButton->Enabled = false;
5209  AZOrderButton->Enabled = false;
5210  TTServiceSyntaxCheckButton->Enabled = false;
5211  NewTTEntryButton->Enabled = false;
5212  MoveTTEntryUpButton->Enabled = false;
5213  MoveTTEntryDownButton->Enabled = false;
5214  CancelTTEntryButton->Enabled = false;
5215  RestoreTTButton->Enabled = false;
5216  ExportTTButton->Enabled = false;
5217  ConflictAnalysisButton->Enabled = false;
5218  ExitTTModeButton->Enabled = true;
5219 
5221  {
5222  AZOrderButton->Enabled = true;
5223  }
5224 
5226  TimetableValidFlag = false; // should always be the case anyway but include here to be sure
5227 
5228  if(CreateEditTTFileName == "")
5229  {
5230  TimetableNameLabel->Caption = "Creating new timetable: not yet saved";
5231  }
5232  else
5233  {
5234  TimetableNameLabel->Caption = "Editing timetable: " + CreateEditTTTitle;
5235  }
5236 
5237  if(TTStartTimePtr != 0) // Null means start time not yet set
5238  {
5239  TTStartTimeBox->Text = (*TTStartTimePtr).SubString(1, 5); // 1st 5 chars = time if validity check OK
5240  }
5241 // start time now set & displayed
5242 
5244  {
5245  InfoPanel->Visible = true;
5246  InfoPanel->Caption = "Select option or change entry";
5247  if(RailwayTitle != "")
5248  {
5249  ShowHideTTButton->Enabled = true;
5250  }
5251  else
5252  {
5253  ShowHideTTButton->Enabled = false;
5254  }
5255  ExitTTModeButton->Enabled = true;
5256  AllEntriesTTListBox->Enabled = true;
5257  AnsiString AnsiAddSubText(AddSubMinsBox->Text);
5258  if((AnsiAddSubText != "") && AreAnyTimesInCurrentEntry())
5259  {
5260  bool ValidFlag = true;
5261  for(int x = 1; x <= AnsiAddSubText.Length(); x++)
5262  {
5263  if((AnsiAddSubText[x] > '9') || (AnsiAddSubText[x] < '0'))
5264  {
5265  ValidFlag = false;
5266  break;
5267  }
5268  }
5269  if(ValidFlag)
5270  {
5271  if(AnsiAddSubText.ToInt() != 0)
5272  {
5273  AddMinsButton->Enabled = true;
5274  SubMinsButton->Enabled = true;
5275  }
5276  }
5277  }
5279  {
5280  RestoreTTButton->Enabled = true;
5281  }
5283  { // Need !TimetableChangedFlag because the changed TT must be saved before validation - it's the TT file that is checked
5284  // so if it is changed but not saved, the 'correct' file will check OK but the changed TT may well not be valid
5285  ValidateTimetableButton->Enabled = true;
5286  }
5288  {
5289  ExportTTButton->Enabled = true;
5290  ConflictAnalysisButton->Enabled = true;
5291  }
5292  if(TTCurrentEntryPtr != 0)
5293  {
5294  CopyTTEntryButton->Enabled = true;
5295  CutTTEntryButton->Enabled = true;
5296  DeleteTTEntryButton->Enabled = true;
5297  }
5298  if((TimetableChangedFlag) && !TimetableEditVector.empty())
5299  {
5300  SaveTTButton->Enabled = true;
5301  }
5302  if(!TimetableEditVector.empty())
5303  {
5304  SaveTTAsButton->Enabled = true;
5305  }
5307  {
5308  NewTTEntryButton->Enabled = true;
5309  }
5310  if((TTCurrentEntryPtr > 0) && !TimetableEditVector.empty())
5311  {
5312  if((TimetableEditVector.end() - 1) > TTCurrentEntryPtr)
5313  {
5314  NextTTEntryButton->Enabled = true;
5315  MoveTTEntryDownButton->Enabled = true;
5316  }
5318  {
5319  PreviousTTEntryButton->Enabled = true;
5320  MoveTTEntryUpButton->Enabled = true;
5321  }
5322  }
5323  if(TTCurrentEntryPtr > 0)
5324  {
5325  if(*TTCurrentEntryPtr != "")
5326  {
5328  {
5329  TTServiceSyntaxCheckButton->Enabled = true;
5330  }
5331  }
5332  }
5333  if(CopiedEntryFlag)
5334  {
5335  PasteTTEntryButton->Enabled = true;
5336  }
5337  OneEntryTimetableMemo->Clear(); // don't clear if Entry changed
5338  if(TTCurrentEntryPtr > 0)
5339  {
5340 // if(*TTCurrentEntryPtr != "") leave this out or fails to highlight blank line entries
5342  {
5343  bool ServiceEntry = true;
5344  DisplayOneTTLineInPanel(0, *TTCurrentEntryPtr, ServiceEntry);
5345  }
5346  else
5347  {
5348  bool ServiceEntry = false;
5349  DisplayOneTTLineInPanel(1, *TTCurrentEntryPtr, ServiceEntry);
5350  }
5351  }
5352  }
5353  else
5354  {
5355  CancelTTEntryButton->Enabled = true;
5356  SaveTTEntryButton->Enabled = true;
5357  ShowHideTTButton->Enabled = false;
5358  ExitTTModeButton->Enabled = false;
5359  AllEntriesTTListBox->Enabled = false; // to stop entries being selected
5360  InfoPanel->Caption = "Add or change entry then save it, or cancel";
5361  InfoPanel->Visible = true;
5362  }
5363  Utilities->CallLogPop(1600);
5364 }
5365 
5366 // ---------------------------------------------------------------------------
5367 void TInterface::DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
5368 {
5369  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisplayOneTTLineInPanel," + Data + ", " +
5370  AnsiString((short)ServiceEntry));
5371  OneEntryTimetableMemo->Clear();
5372  if(ServiceEntry)
5373  {
5374  TrainController->StripSpaces(1, Data);
5375  while(true)
5376  {
5377  int CommaPos = Data.Pos(',');
5378  if((CommaPos == 0) && (Data != ""))
5379  {
5380  CommaPos = Data.Length() + 1;
5381  }
5382  OneEntryTimetableMemo->Lines->Add(Data.SubString(1, CommaPos - 1));
5383  if(Data.Length() <= CommaPos)
5384  break;
5385  Data = Data.SubString(CommaPos + 1, Data.Length() - CommaPos);
5386  }
5387  }
5388  else
5389  {
5390  OneEntryTimetableMemo->Text = Data;
5391  }
5392  int TotalLines = OneEntryTimetableMemo->Lines->Count; // remove excess lines at bottom
5393 
5394  while((OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "") || (OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "\r\n"))
5395  {
5396  OneEntryTimetableMemo->Lines->Delete(TotalLines - 1);
5397  TotalLines--;
5398  if(TotalLines < 1)
5399  break;
5400  }
5401  OneEntryTimetableMemo->HideSelection = true;
5402  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
5403  OneEntryTimetableMemo->SelLength = 0;
5405  Utilities->CallLogPop(1602);
5406 }
5407 // ---------------------------------------------------------------------------
5408 
5410 {
5411  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighlightOneEntryInAllEntriesTTListBox," + AnsiString(Position));
5412  if(TimetableEditVector.empty() || (AllEntriesTTListBox->Items->Count == 0))
5413  {
5414  HighlightPanel->Top = 32;
5415  HighlightPanel->Caption = "";
5416  HighlightPanel->Width = 100;
5417  HighlightPanel->Visible = false;
5418  }
5419  else
5420  {
5421  AnsiString CurrentStr = AllEntriesTTListBox->Items->Strings[Position];
5422  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5423  {
5424  for(int x = 1; x < CurrentStr.Length(); x++)
5425  {
5426  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5427  {
5428  CurrentStr = CurrentStr.SubString(1, (x - 1));
5429  }
5430  }
5431  }
5432  HighlightPanel->Top = 32 + (Position * 13) - (AllEntriesTTListBox->TopIndex * 13);
5433  if(HighlightPanel->Top < 32)
5434  HighlightPanel->Visible = false;
5435  else
5436  HighlightPanel->Visible = true; // doesn't matter if goes off the bottom as it becomes invisible as then it's off its parent panel
5437  HighlightPanel->Caption = CurrentStr;
5438  if(AllEntriesTTListBox->Items->Count > 47) //because the scrollbar will be present
5439  HighlightPanel->Width = 82;
5440  else
5441  HighlightPanel->Width = 100;
5442  }
5443  Utilities->CallLogPop(1709);
5444 }
5445 
5446 // ---------------------------------------------------------------------------
5448 {
5449  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == ""))
5450  {
5451  return false;
5452  }
5453  TDateTime DummyTime;
5454  bool TimesPresent = false;
5455 
5456  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
5457  {
5458  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
5459  {
5460  if(TrainController->CheckTimeValidity(20, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
5461  {
5462  TimesPresent = true;
5463  break;
5464  }
5465  }
5466  if(TimesPresent)
5467  break;
5468  }
5469  return TimesPresent;
5470 }
5471 
5472 // ---------------------------------------------------------------------------
5473 // end of Timetable editing functions
5474 // ---------------------------------------------------------------------------
5475 void __fastcall TInterface::ExitMenuItemClick(TObject *Sender)
5476 {
5477  try
5478  {
5479  TrainController->LogEvent("ExitMenuItemClick");
5480  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitMenuItemClick");
5482  {
5483  UnicodeString MessageStr =
5484  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
5485  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5486  if(button == IDNO)
5487  {
5488  Utilities->CallLogPop(1711);
5489  return;
5490  }
5491  }
5492  if(FileChangedFlag)
5493  {
5494  UnicodeString MessageStr = "The railway has changed, exit without saving?";
5495  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5496  if(button == IDNO)
5497  {
5498  Utilities->CallLogPop(1180);
5499  return;
5500  }
5501  }
5502  if((TempTTFileName != "") && FileExists(TempTTFileName))
5503  {
5504  DeleteFile(TempTTFileName);
5505  }
5506  Utilities->CallLogPop(1181);
5507  Application->Terminate();
5508  }
5509  catch(const Exception &e)
5510  {
5511  ErrorLog(140, e.Message);
5512  }
5513 }
5514 // ---------------------------------------------------------------------------
5515 
5516 void __fastcall TInterface::TrackInfoOnOffMenuItemClick(TObject *Sender)
5517 {
5518  try
5519  {
5520  TrainController->LogEvent("TrackInfoOnOffMenuItemClick");
5521  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackInfoOnOffMenuItemClick");
5522  if(TrackInfoOnOffMenuItem->Caption == "Show")
5523  {
5524  TrackInfoOnOffMenuItem->Caption = "Hide";
5525  }
5526  else
5527  {
5528  TrackInfoOnOffMenuItem->Caption = "Show";
5529  }
5530  Utilities->CallLogPop(1183);
5531  }
5532  catch(const Exception &e)
5533  {
5534  ErrorLog(173, e.Message);
5535  }
5536 }
5537 // ---------------------------------------------------------------------------
5538 
5539 void __fastcall TInterface::TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
5540 {
5541  try
5542  {
5543  TrainController->LogEvent("TrainStatusInfoOnOffMenuItemClick");
5544  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainStatusInfoOnOffMenuItemClick");
5545  if(TrainStatusInfoOnOffMenuItem->Caption == "Show Status")
5546  {
5547  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status";
5548  }
5549  else
5550  {
5551  TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
5552  }
5553  Utilities->CallLogPop(1184);
5554  }
5555  catch(const Exception &e)
5556  {
5557  ErrorLog(141, e.Message);
5558  }
5559 }
5560 
5561 // ---------------------------------------------------------------------------
5562 void __fastcall TInterface::TrainTTInfoOnOffMenuItemClick(TObject *Sender)
5563 {
5564  try
5565  {
5566  TrainController->LogEvent("TrainTTInfoOnOffMenuItemClick");
5567  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainTTInfoOnOffMenuItemClick");
5568  if(TrainTTInfoOnOffMenuItem->Caption == "Show Timetable")
5569  {
5570  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable";
5571  }
5572  else
5573  {
5574  TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
5575  }
5576  Utilities->CallLogPop(1185);
5577  }
5578  catch(const Exception &e)
5579  {
5580  ErrorLog(142, e.Message);
5581  }
5582 }
5583 
5584 // ---------------------------------------------------------------------------
5585 // Dragging Functions
5586 // ---------------------------------------------------------------------------
5587 void __fastcall TInterface::AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
5588 {
5589 // allow in zoom out mode
5590  try
5591  {
5592 // TrainController->LogEvent("AcceptDragging"); drop this, have too many
5593  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AcceptDragging");
5594  if((Source == PerformancePanel) || (Source == PerformancePanelLabel) || (Source == PerformanceLogBox))
5595  {
5596  Accept = true;
5597  int PPLeft = PerformancePanel->Left;
5598  int PPTop = PerformancePanel->Left;
5599 
5600  PPLeft = Mouse->CursorPos.x - PerformancePanelDragStartX;
5601  PPTop = Mouse->CursorPos.y - PerformancePanelDragStartY;
5602  if((PPLeft + PerformancePanel->Width) < 32)
5603  PPLeft = 32 - PerformancePanel->Width;
5604  if(PPLeft > (MainScreen->Left + MainScreen->Width))
5605  PPLeft = MainScreen->Left + MainScreen->Width;
5606  if((PPTop + PerformancePanel->Height) < MainScreen->Top)
5607  PPTop = MainScreen->Top - PerformancePanel->Height;
5608  if(PPTop > (MainScreen->Top + MainScreen->Height - 20))
5609  PPTop = MainScreen->Top + MainScreen->Height - 20;
5610  PerformancePanel->Left = PPLeft;
5611  PerformancePanel->Top = PPTop;
5612  }
5613  else if((Source == OperatorActionPanel) || (Source == OAPanelLabel))
5614  // not the listbox because that used for selecting trains
5615  {
5616  Accept = true;
5617  int OALeft = OperatorActionPanel->Left;
5618  int OATop = OperatorActionPanel->Left;
5619 
5620  OALeft = Mouse->CursorPos.x - OperatorActionPanelDragStartX;
5621  OATop = Mouse->CursorPos.y - OperatorActionPanelDragStartY;
5622  if((OALeft + OperatorActionPanel->Width) < 32)
5623  OALeft = 32 - OperatorActionPanel->Width;
5624  if(OALeft > (MainScreen->Left + MainScreen->Width))
5625  OALeft = MainScreen->Left + MainScreen->Width;
5626  if((OATop + OperatorActionPanel->Height) < MainScreen->Top)
5627  OATop = MainScreen->Top - OperatorActionPanel->Height;
5628  if(OATop > (MainScreen->Top + MainScreen->Height - 20))
5629  OATop = MainScreen->Top + MainScreen->Height - 20;
5630  OperatorActionPanel->Left = OALeft;
5631  OperatorActionPanel->Top = OATop;
5632  }
5633  else
5634  Accept = false;
5635  Utilities->CallLogPop(1186);
5636  }
5637  catch(const Exception &e)
5638  {
5639  ErrorLog(143, e.Message);
5640  }
5641 }
5642 
5643 // ---------------------------------------------------------------------------
5644 void __fastcall TInterface::PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
5645 {
5646 // allow in zoom out mode
5647  try
5648  {
5649  TrainController->LogEvent("PerformancePanelStartDrag");
5650  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelStartDrag");
5651  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
5652  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
5653  Utilities->CallLogPop(1187);
5654  }
5655  catch(const Exception &e)
5656  {
5657  ErrorLog(144, e.Message);
5658  }
5659 }
5660 // ---------------------------------------------------------------------------
5661 
5662 void __fastcall TInterface::OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject) // new v2.2.0
5663 
5664 {
5665 // allow in zoom out mode
5666  try
5667  {
5668  TrainController->LogEvent("OperatorActionPanelStartDrag");
5669  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionPanelStartDrag");
5670  OperatorActionPanelDragStartX = Mouse->CursorPos.x - OperatorActionPanel->Left;
5671  OperatorActionPanelDragStartY = Mouse->CursorPos.y - OperatorActionPanel->Top;
5672  Utilities->CallLogPop(2091);
5673  }
5674  catch(const Exception &e)
5675  {
5676  ErrorLog(201, e.Message);
5677  }
5678 }
5679 
5680 // ---------------------------------------------------------------------------
5681 // Mouse Functions
5682 // ---------------------------------------------------------------------------
5683 void __fastcall TInterface::MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
5684  // caller function - stops master clock
5685 {
5686 // have to allow in zoom out mode
5687  try
5688  {
5689  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseDown," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5690  bool ClockState = Utilities->Clock2Stopped;
5691  Utilities->Clock2Stopped = true;
5692 
5693  RestoreFocusPanel->Enabled = true; // these added at v2.0.0 to restore navigation keys to move screen when a panel had focus
5694  RestoreFocusPanel->Visible = true; // because then these buttons just cycled through the panel buttons. Added in place of the
5695  RestoreFocusPanel->SetFocus(); // section in ClockTimer2 where focus restored every clock cycle, because then the help screen
5696  RestoreFocusPanel->Visible = false; // was hidden. At least now help is only hidden when the screen clicked, which is normal
5697  RestoreFocusPanel->Enabled = false; // behaviour, and can tell user that can restore navigation keys just by clicking the screen
5698 
5700  {
5701  if(!Display->ZoomOutFlag)
5702  MainScreenMouseDown2(0, Button, Shift, X, Y);
5703  else
5704  MainScreenMouseDown3(0, Button, Shift, X, Y);
5705  }
5706  Utilities->Clock2Stopped = ClockState;
5707  Utilities->CallLogPop(33);
5708  }
5709  catch(const Exception &e)
5710  {
5711  ErrorLog(19, e.Message);
5712  }
5713 }
5714 
5715 // ---------------------------------------------------------------------------
5716 void TInterface::MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
5717 {
5718  try
5719  {
5720  TrainController->LogEvent("MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5721  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) +
5722  "," + AnsiString(Y));
5723  // unplot GapFlash graphics if plotted & cancel gap flashing if left mouse button pressed (so can move display with right mouse button)
5724  // but not in ZoomOut mode - so can switch between modes & keep gaps flashing
5725  if(Track->GapFlashFlag && !Display->ZoomOutFlag && (Button == mbLeft))
5726  {
5729  Track->GapFlashFlag = false;
5730  }
5731  int HLoc, VLoc;
5732  Track->GetTrackLocsFromScreenPos(1, HLoc, VLoc, X, Y);
5733  int NoOffsetX, NoOffsetY;
5734  Track->GetTruePositionsFromScreenPos(0, NoOffsetX, NoOffsetY, X, Y);
5735  if(Button == mbRight) // track, PrefDir or text erase, PrefDir/route truncate, or take signaller control of train
5736  {
5737  // this routine new at v2.1.0. Allows railway moving for zoom-in mode when no element at HLoc & VLoc
5738  int Dummy; // unused in next function
5739  AnsiString Text = ""; //needed for TextFound but not used
5740  if(!Track->TrackElementPresentAtHV(0, HLoc, VLoc) && !Track->InactiveTrackElementPresentAtHV(0, HLoc, VLoc) && !Track->UserGraphicPresentAtHV(0, X, Y, Dummy) &&
5741  !TextHandler->TextFound(0, X + (Display->DisplayOffsetH * 16), Y + (Display->DisplayOffsetV * 16), Text))
5742  {
5745  WholeRailwayMoving = true;
5746  Screen->Cursor = TCursor(-22); // Four arrows;
5747  }
5748 
5749  else if(Level2TrackMode == AddText)
5750  {
5751  TrainController->LogEvent("mbRight + AddText");
5753  if(TextHandler->TextFound(1, NoOffsetX, NoOffsetY, Text))
5754  {
5755  if(TextHandler->TextErase(0, NoOffsetX, NoOffsetY, Text)) // erase text in vector
5756  {
5758  if(NoRailway())
5759  {
5760  EditMenu->Enabled = false;
5761  }
5762  else
5763  EditMenu->Enabled = true;
5764  }
5765  }
5766  SetLevel2TrackMode(57); // to remove 'move text' if last text item removed
5767  Utilities->CallLogPop(34);
5768  return;
5769  }
5770  else if(Level2TrackMode == AddGraphic)
5771  {
5772  TrainController->LogEvent("mbRight + AddGraphic");
5773  if(Track->UserGraphicVector.empty()) // no user graphics
5774  {
5775  Utilities->CallLogPop(2180);
5776  return;
5777  }
5778  int UGIVecPos;
5779  if(Track->UserGraphicPresentAtHV(1, X, Y, UGIVecPos))
5780  {
5781  Track->UserGraphicVector.erase(Track->UserGraphicVector.begin() + UGIVecPos);
5783  if(NoRailway())
5784  {
5785  EditMenu->Enabled = false;
5786  }
5787  else
5788  EditMenu->Enabled = true;
5789  }
5790  Utilities->CallLogPop(2181);
5791  return;
5792  }
5793 
5794  else if(Level2TrackMode == AddTrack)
5795  {
5796  TrainController->LogEvent("mbRight + AddTrack");
5797  bool TrackEraseSuccessfulFlag;
5798  int ErasedTrackVectorPosition;
5799  Screen->Cursor = TCursor(-11); // Hourglass;
5800  Track->EraseTrackElement(1, HLoc, VLoc, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, true);
5801  if(TrackEraseSuccessfulFlag)
5802  {
5803  if(ErasedTrackVectorPosition > -1)
5804  EveryPrefDir->RealignAfterTrackErase(0, ErasedTrackVectorPosition);
5807  ClearandRebuildRailway(5); // to ensure location named elements plotted correctly & replot the grid if required
5808  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
5809  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
5810  if(Track->GapsUnset(1))
5811  {
5812  SetGapsButton->Enabled = true;
5813  }
5814  // only enable if there are gaps still to be set (returns false for no track)
5815  else
5816  {
5817  if(!(Track->NoActiveTrack(0)) && !(Track->IsTrackFinished()))
5818  {
5819  TrackOKButton->Enabled = true;
5820  }
5821  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
5822  }
5823  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
5824  {
5825  SetLengthsButton->Enabled = false;
5826  }
5827 // if(NoRailway()) dropped at v2.6.0 to allow edits during AddTrack
5828 // {
5829 // EditMenu->Enabled = false;
5830 // }
5831 // else
5832  EditMenu->Enabled = true;
5833  }
5834  Screen->Cursor = TCursor(-2); // Arrow
5835  Utilities->CallLogPop(35);
5836  return;
5837  }
5838  else if(Level2TrackMode == DistanceContinuing) // new for extended distances (similar to PrefDirContinuing)
5839  {
5840  TrainController->LogEvent("mbRight + DistanceContinuing");
5842  bool LeadingPointsAtLastElement = false;
5843  if(ConstructPrefDir->GetPrefDirTruncateElement(0, HLoc, VLoc))
5844  {
5845  if(ConstructPrefDir->PrefDirSize() == 0)
5846  {
5848  SetLevel1Mode(64);
5850  SetLevel2TrackMode(51); // calls ClearandRebuildRailway to show length erased & sets back to start
5851  Utilities->CallLogPop(1526);
5852  return;
5853  }
5856  ConstructPrefDir->CalcDistanceAndSpeed(0, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
5857  if(!LeadingPointsAtLastElement)
5858  {
5859  TrackLengthPanel->Visible = true;
5860  TrackLengthPanel->SetFocus();
5861  InfoPanel->Visible = true;
5862  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
5863  RestoreAllDefaultLengthsButton->Enabled = true;
5864  ResetDefaultLengthButton->Enabled = true;
5865  LengthOKButton->Enabled = true;
5866  DistanceBox->Text = AnsiString(OverallDistance);
5867  if(OverallSpeedLimit > -1)
5868  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
5869  else
5870  SpeedLimitBox->Text = "Mixed";
5871  }
5872  else
5873  {
5874  TrackLengthPanel->Visible = true;
5875  TrackLengthPanel->SetFocus();
5876  InfoPanel->Visible = true;
5877  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, continue or truncate";
5878  RestoreAllDefaultLengthsButton->Enabled = false;
5879  ResetDefaultLengthButton->Enabled = false;
5880  LengthOKButton->Enabled = false;
5881  }
5883  }
5884  Utilities->CallLogPop(36);
5885  return;
5886  }
5887 
5888  else if(Level2PrefDirMode == PrefDirContinuing) // truncate
5889  {
5890  TrainController->LogEvent("mbRight + PrefDirContinuing");
5892 // RlyFile = false; - don't alter this just for PrefDir changes
5893  if(ConstructPrefDir->GetPrefDirTruncateElement(1, HLoc, VLoc))
5894  {
5895  if(ConstructPrefDir->PrefDirSize() == 0)
5896  {
5898  SetLevel1Mode(14); // all PrefDir truncated
5899  Utilities->CallLogPop(37);
5900  return;
5901  }
5903  }
5905  SetLevel2PrefDirMode(0); // calls ClearandRebuildRailway to show length erased & sets back to start
5906  Utilities->CallLogPop(38);
5907  return;
5908  }
5909 
5910  else if((Level1Mode == PrefDirMode) && (Level2PrefDirMode != PrefDirContinuing) && (Level2PrefDirMode != PrefDirSelecting)) // delete element
5911  {
5912  TrainController->LogEvent("mbRight + != PrefDirContinuing");
5914 // RlyFile = false; - don't alter this just for PrefDir changes
5917  SetLevel1Mode(15); // calls ClearandRebuildRailway to show length erased & sets back to start
5918  Utilities->CallLogPop(39);
5919  return;
5920  }
5921 
5922  else if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // disallow when paused, but allow some parts in prestart
5923  {
5924  TrainController->LogEvent("mbRight + OperMode");
5925  bool FoundFlag;
5926  int VecPos = Track->GetVectorPositionFromTrackMap(1, HLoc, VLoc, FoundFlag);
5927  if(FoundFlag && (Level2OperMode != PreStart)) // disallow signaller control in PreStart
5928  {
5930  // signaller control of train
5931  if(SelectedTrainID > -1)
5932  {
5935  if((Train.LeadElement == -1) || (Track->TrackElementAt(788, Train.LeadElement).Conn[Train.LeadExitPos] == -1))
5936  {
5937  if(Train.TrainMode == Signaller)
5938  {
5940  }
5941  }
5942  if((Train.Stopped()) || (Train.TrainFailed && !(Train.TrainMode == Signaller)) ||
5944  !Train.StepForwardFlag))
5945  // don't allow signaller popup menu in timetable mode unless stopped,
5946  // or when coming to a stop or leaving at a continuation when under signaller control
5947  // or when failed
5948  {
5949  // don't allow selection if another stopped train at a bridge position
5950  if(Track->TrackElementAt(630, VecPos).TrackType == Bridge)
5951  {
5952  int TrainID01 = Track->TrackElementAt(631, VecPos).TrainIDOnBridgeTrackPos01;
5953  int TrainID23 = Track->TrackElementAt(632, VecPos).TrainIDOnBridgeTrackPos23;
5954  if((TrainID01 > -1) && (TrainID23 > -1))
5955  {
5956  TrainController->StopTTClockMessage(0, "Can't select a train at a bridge when another train is at the same bridge");
5957  Utilities->CallLogPop(1103);
5958  return;
5959  }
5960  }
5961  if(Train.TrainMode == Timetable)
5962  {
5963  TakeSignallerControlMenuItem->Enabled = true;
5964  TimetableControlMenuItem->Enabled = false;
5965  ChangeDirectionMenuItem->Enabled = false;
5966  MoveForwardsMenuItem->Enabled = false;
5967  SignallerJoinedByMenuItem->Enabled = false;
5968  RepairFailedTrainMenuItem->Enabled = false;
5969  StepForwardMenuItem->Enabled = false;
5970  RemoveTrainMenuItem->Enabled = false;
5971  PassRedSignalMenuItem->Enabled = false;
5972  SignallerControlStopMenuItem->Enabled = false;
5973  }
5974  else // signaller mode
5975  {
5976  TakeSignallerControlMenuItem->Enabled = false;
5977  if((Train.Crashed) || (Train.Derailed))
5978  {
5979  TimetableControlMenuItem->Enabled = false;
5980  ChangeDirectionMenuItem->Enabled = false;
5981  MoveForwardsMenuItem->Enabled = false;
5982  SignallerJoinedByMenuItem->Enabled = false;
5983  RepairFailedTrainMenuItem->Enabled = false;
5984  StepForwardMenuItem->Enabled = false;
5985  PassRedSignalMenuItem->Enabled = false;
5986  SignallerControlStopMenuItem->Enabled = false;
5987  RemoveTrainMenuItem->Enabled = true;
5988  }
5989  else if(Train.Stopped())
5990  {
5991  if(Train.TimetableFinished)
5992  {
5993  TimetableControlMenuItem->Enabled = false;
5994  }
5995  else
5996  {
5997  if(Train.RestoreTimetableLocation == "") // en route
5998  {
5999  TimetableControlMenuItem->Enabled = true;
6000  }
6001  else
6002  {
6003  // obtain train location & check if OK for restoration of tt control
6004  AnsiString LocName = "";
6005  if(Train.LeadElement > -1)
6006  {
6007  LocName = Track->TrackElementAt(802, Train.LeadElement).ActiveTrackElementName;
6008  }
6009  if((LocName == "") && (Train.MidElement > -1))
6010  {
6011  LocName = Track->TrackElementAt(803, Train.MidElement).ActiveTrackElementName;
6012  }
6013  if(Train.RestoreTimetableLocation == LocName)
6014  {
6015  TimetableControlMenuItem->Enabled = true;
6016  }
6017  else
6018  {
6019  TimetableControlMenuItem->Enabled = false;
6020  }
6021  }
6022  }
6023 // don't allow ChangeDirection if lead or mid elements (but not lag or next) -1, or lead, mid, lag or next elements continuations
6024  ChangeDirectionMenuItem->Enabled = true;
6025  if(Train.LeadElement > -1)
6026  {
6028  {
6029  ChangeDirectionMenuItem->Enabled = false;
6030  }
6031  if(Track->TrackElementAt(791, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
6032  {
6033  if(Track->TrackElementAt(792, (Track->TrackElementAt(793, Train.LeadElement).Conn[Train.LeadExitPos]))
6034  .TrackType == Continuation)
6035  {
6036  ChangeDirectionMenuItem->Enabled = false;
6037  }
6038  }
6039  }
6040  else
6041  ChangeDirectionMenuItem->Enabled = false;
6042  if(Train.MidElement > -1)
6043  {
6045  {
6046  ChangeDirectionMenuItem->Enabled = false;
6047  }
6048  }
6049  else
6050  ChangeDirectionMenuItem->Enabled = false;
6051  if(Train.LagElement > -1)
6052  {
6054  {
6055  ChangeDirectionMenuItem->Enabled = false;
6056  }
6057  }
6058  RemoveTrainMenuItem->Enabled = true;
6059  SignallerControlStopMenuItem->Enabled = false;
6060  SignallerJoinedByMenuItem->Enabled = false;
6061  RepairFailedTrainMenuItem->Enabled = false;
6062  StepForwardMenuItem->Enabled = false;
6063  MoveForwardsMenuItem->Enabled = false;
6064  PassRedSignalMenuItem->Enabled = false;
6065  if(Train.AbleToMove(0))
6066  {
6067  MoveForwardsMenuItem->Enabled = true;
6069  StepForwardMenuItem->Enabled = true; // added 'if' condition for v1.3.2 due to Carwyn Thomas error,
6070  } // fails on trying to calc AutoSig time delay for resetting signals
6071  if(Train.AbleToMoveButForSignal(0)) // may not be in AutoSigs route but disallow anyway as not needed at continuation
6072  {
6073  PassRedSignalMenuItem->Enabled = true;
6074  StepForwardMenuItem->Enabled = true;
6075  }
6076  TTrain *AdjacentTrain;
6077  if(Train.IsThereAnAdjacentTrain(0, AdjacentTrain))
6078  {
6079  SignallerJoinedByMenuItem->Enabled = true;
6080  }
6081  if(Train.TrainFailed)
6082  {
6083  RepairFailedTrainMenuItem->Enabled = true;
6084  }
6085  }
6086  else // train moving under signaller control - only permit restoration of TT control when stopped as could be in
6087  // mid move, & SetTrainMovementValues only intended to be called when stopped
6088  {
6089  TimetableControlMenuItem->Enabled = false;
6090  ChangeDirectionMenuItem->Enabled = false;
6091  RemoveTrainMenuItem->Enabled = false;
6092  MoveForwardsMenuItem->Enabled = false;
6093  SignallerJoinedByMenuItem->Enabled = false;
6094  RepairFailedTrainMenuItem->Enabled = false;
6095  PassRedSignalMenuItem->Enabled = false;
6096  StepForwardMenuItem->Enabled = false;
6097  SignallerControlStopMenuItem->Enabled = true;
6098  }
6099  }
6100  TrainHeadCodeMenuItem->Caption = Train.HeadCode + ":";
6101  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6103  PopupMenu->Popup(MainScreen->Left+X, MainScreen->Top+Y+43); //menu stops everything so reset timetable time when restarts,
6104  //new at v2.6.1, displays so that can't inadvertently click on a selection if click twice
6105  //43 is the distance from the top of the screen to the top of TInterface
6106  TrainController->BaseTime = TDateTime::CurrentDateTime();
6108  Utilities->CallLogPop(40);
6109  return;
6110  }
6111  }
6112  }
6113 
6114  if(RouteMode == RouteContinuing) // clear a single element (clears whether use left or right mouse button) +allow in PreStart
6115  {
6116  TrainController->LogEvent("mbRight + RouteContinuing");
6118  Utilities->CallLogPop(41);
6119  return;
6120  }
6121 
6122  else if(RouteCancelFlag) // allow in PreStart
6123  {
6124  TrainController->LogEvent("mbRight + RouteCancelFlag");
6125  Screen->Cursor = TCursor(-11); // Hourglass;
6126  // stop clock as sometimes takes several seconds
6127  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6129  if(AllRoutes->GetAllRoutesTruncateElement(0, HLoc, VLoc, ConsecSignalsRoute)) // updates LockedRouteClass
6130  {
6131  ClearandRebuildRailway(6); // to replot new shorter route
6132  }
6134  TrainController->BaseTime = TDateTime::CurrentDateTime();
6136  Screen->Cursor = TCursor(-2); // Arrow
6137  }
6138 
6139  else // gap flashing, don't allow to interfere with RouteCancelFlag
6140  {
6141  TrainController->LogEvent("mbRight, GapFlashingInOperOrPreStartMode");
6142  int Position;
6143  TTrackElement TrackElement;
6144  if(Track->FindNonPlatformMatch(4, HLoc, VLoc, Position, TrackElement));
6145  {
6146  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
6147  {
6148  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(818, TrackElement.Conn[0]).TrainIDOnElement == -1))
6149  { // don't flash if train on either gap element
6150  Track->GapFlashGreenPosition = TrackElement.Conn[0];
6155  Track->GapFlashRedPosition = Position;
6160  Track->GapFlashFlag = true;
6161  }
6162  }
6163  }
6164  Utilities->CallLogPop(42);
6165  return; // covers above else & included here in case any more usermodes added later
6166  }
6167  }
6168 
6169  // deal with gap selection - if no other right button selection - apply for any mode (also included in OperMode above)
6170  TrainController->LogEvent("mbRight, GapFlashingNotOperOrPreStartMode");
6171  int Position;
6172  TTrackElement TrackElement;
6173  if(Track->FindNonPlatformMatch(18, HLoc, VLoc, Position, TrackElement));
6174  {
6175  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
6176  {
6177  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(819, TrackElement.Conn[0]).TrainIDOnElement == -1))
6178  { // don't flash if train on either gap element
6179  Track->GapFlashGreenPosition = TrackElement.Conn[0];
6183  Track->GapFlashRedPosition = Position;
6187  Track->GapFlashFlag = true;
6188  }
6189  }
6190  }
6191  Utilities->CallLogPop(67);
6192  return; // covers above else & included here in case any more usermodes added later
6193  }
6194 
6195 // Left Mouse Button Functions
6196  if(RouteCancelFlag)
6198  mbLeftDown = true;
6199 
6200  if(Level2TrackMode == AddTrack)
6201  {
6202  TrainController->LogEvent("mbLeft + AddTrack");
6203  Screen->Cursor = TCursor(-11); // Hourglass;
6205  bool TrackLinkingRequiredFlag;
6206  int CurrentTag;
6207  TSpeedButton *TempSpeedButton = 0;
6208  if(CurrentSpeedButton)
6209  {
6210  CurrentTag = CurrentSpeedButton->Tag;
6211  TempSpeedButton = CurrentSpeedButton;
6212  }
6213  else
6214  CurrentTag = 0;
6215  bool InternalChecks = true;
6216  Track->PlotAndAddTrackElement(1, CurrentTag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, InternalChecks);
6217  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
6218  EditMenu->Enabled = true;
6219  if(Track->NamedLocationElementAt(1, HLoc, VLoc))
6220  ClearandRebuildRailway(7); // so named location graphics plotted correctly
6221  if(TrackLinkingRequiredFlag)
6222  {
6223  Track->SetTrackFinished(false);
6224  }
6225  SetTrackBuildImages(10);
6226  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
6227  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
6228  if(Track->GapsUnset(2))
6229  {
6230  SetGapsButton->Enabled = true;
6231  }
6232  // only enable if there are gaps still to be set (returns false for no track)
6233  else
6234  {
6235  if(!(Track->NoActiveTrack(1)) && !(Track->IsTrackFinished()))
6236  {
6237  TrackOKButton->Enabled = true;
6238  }
6239  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
6240  }
6241  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
6242  {
6243  SetLengthsButton->Enabled = false;
6244  }
6245  if(TempSpeedButton) // restore button if was pressed
6246  {
6247  CurrentSpeedButton = TempSpeedButton;
6248  CurrentSpeedButton->Down = true;
6249  }
6250  Screen->Cursor = TCursor(-2); // Arrow
6251  Utilities->CallLogPop(44);
6252  return;
6253  }
6254 
6255  else if(Level2TrackMode == AddGraphic)
6256  {
6257  TrainController->LogEvent("mbLeft + AddGraphic");
6258  ResetChangedFileDataAndCaption(24, false);
6259  TUserGraphicItem NewGI;
6260  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
6261  if(UGMIt != Track->UserGraphicMap.end()) // if it is the end then nothing was found
6262  {
6263  NewGI.UserGraphic = UGMIt->second;
6264  NewGI.Width = UGMIt->second->Width;
6265  NewGI.Height = UGMIt->second->Height;
6267  NewGI.HPos = X + (Display->DisplayOffsetH * 16);
6268  NewGI.VPos = Y + (Display->DisplayOffsetV * 16);
6269  Track->UserGraphicVector.push_back(NewGI);
6270  Display->PlotAndAddUserGraphic(1, NewGI);
6271  }
6272  else
6273  {
6274  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
6275  Utilities->CallLogPop(2195);
6276  return;
6277  }
6278  MoveTextOrGraphicButton->Enabled = true;
6279  EditMenu->Enabled = true;
6280  Utilities->CallLogPop(2182);
6281  return;
6282  }
6283 
6284  else if(Level2TrackMode == AddLocationName)
6285  {
6286  TrainController->LogEvent("mbLeft + AddLocationName");
6288  bool FoundFlag;
6289  TTrackElement TrackElement;
6290  AnsiString NameString;
6291  TTrack::TIMPair InactivePair = Track->GetVectorPositionsFromInactiveTrackMap(1, HLoc, VLoc, FoundFlag);
6292  if(!FoundFlag)
6293  {
6294  Utilities->CallLogPop(45);
6295  return; // inactive element not found (has to be a platform or named non-station location, can't select any other element)
6296  }
6297  TTrackElement& InactiveTrackElement1 = Track->InactiveTrackElementAt(28, InactivePair.first);
6298  TTrackElement& InactiveTrackElement2 = Track->InactiveTrackElementAt(29, InactivePair.second); // may be same element if only 1
6299  TTrackElement& ValidElement = InactiveTrackElement1;
6300  unsigned int ValidPosition;
6301  if((InactiveTrackElement1.TrackType != Platform) && (InactiveTrackElement2.TrackType != Platform) &&
6302  (InactiveTrackElement1.TrackType != NamedNonStationLocation) && (InactiveTrackElement2.TrackType != NamedNonStationLocation) &&
6303  (InactiveTrackElement1.TrackType != Concourse) && (InactiveTrackElement2.TrackType != Concourse))
6304  {
6305  Utilities->CallLogPop(46);
6306  return; // element not valid
6307  }
6308  if((InactiveTrackElement1.TrackType == Platform) || (InactiveTrackElement1.TrackType == NamedNonStationLocation) ||
6309  (InactiveTrackElement1.TrackType == Concourse))
6310  {
6311  ValidElement = InactiveTrackElement1;
6312  ValidPosition = InactivePair.first;
6313  }
6314  else if((InactiveTrackElement2.TrackType == Platform) || (InactiveTrackElement2.TrackType == NamedNonStationLocation) ||
6315  (InactiveTrackElement2.TrackType == Concourse))
6316  {
6317  ValidElement = InactiveTrackElement2;
6318  ValidPosition = InactivePair.second;
6319  }
6320  // now have required element as ValidElement & position in InactiveTrackvector as ValidPosition
6321 
6322  // put a square box round element to show selection
6323  Display->Rectangle(0, HLoc * 16, VLoc * 16, clB0G0R5, 0, 2);
6324  LocationNameTextBox->Visible = true;
6325  LocationNameTextBox->SetFocus();
6326  NameString = Track->GetLocationName(ValidPosition);
6327  LocationNameTextBox->Text = NameString;
6328  InfoPanel->Visible = true;
6329  InfoPanel->Caption = "NAMING LOCATIONS: Enter name, 'Carriage Return' to accept, 'Escape' to quit";
6330 
6331  Track->LNPendingList.clear();
6332  Track->LNPendingList.insert(Track->LNPendingList.end(), ValidPosition);
6333  Level2TrackMode = NoTrackMode; // if leave as AddLocationName can select other squares before enter name
6334  Utilities->CallLogPop(47);
6335  return;
6336  }
6337 
6338  else if(Level2TrackMode == DistanceStart) // new for extended distances - similar to !PrefDirContinuing
6339  // prior to selecting start element
6340  {
6341  TrainController->LogEvent("mbLeft + DistanceStart");
6343  if(ConstructPrefDir->GetPrefDirStartElement(0, HLoc, VLoc))
6344  {
6347  SetLevel1Mode(65);
6349  SetLevel2TrackMode(30);
6350  }
6351  Utilities->CallLogPop(48);
6352  return;
6353  }
6354 
6355  else if(Level2TrackMode == DistanceContinuing) // new for extended distances - similar to PrefDirContinuing
6356  // prior to selecting finish element
6357  {
6358  TrainController->LogEvent("mbLeft + DistanceContinuing");
6360  bool FinishElement = false, LeadingPointsAtLastElement = false;
6361  Screen->Cursor = TCursor(-11); // Hourglass;
6362  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(181, 0).HLoc != HLoc) ||
6363  (ConstructPrefDir->GetFixedPrefDirElementAt(182, 0).VLoc != VLoc))
6364  { // not same as start element
6365  if(ConstructPrefDir->GetNextPrefDirElement(0, HLoc, VLoc, FinishElement))
6366  {
6369  ConstructPrefDir->CalcDistanceAndSpeed(1, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
6370  if(FinishElement)
6371  {
6372  TrackLengthPanel->Visible = true;
6373  TrackLengthPanel->SetFocus();
6374  InfoPanel->Visible = true;
6375  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values (overall length), or right click to cancel/truncate";
6376  RestoreAllDefaultLengthsButton->Enabled = true;
6377  ResetDefaultLengthButton->Enabled = true;
6378  LengthOKButton->Enabled = true;
6379  DistanceBox->Text = AnsiString(OverallDistance);
6380  if(OverallSpeedLimit > -1)
6381  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6382  else
6383  SpeedLimitBox->Text = "Mixed";
6385  Screen->Cursor = TCursor(-2); // Arrow
6386  Utilities->CallLogPop(1527);
6387  return;
6388  }
6389  else
6390  {
6391  if(!LeadingPointsAtLastElement)
6392  {
6393  TrackLengthPanel->Visible = true;
6394  TrackLengthPanel->SetFocus();
6395  InfoPanel->Visible = true;
6396  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
6397  RestoreAllDefaultLengthsButton->Enabled = true;
6398  ResetDefaultLengthButton->Enabled = true;
6399  LengthOKButton->Enabled = true;
6400  DistanceBox->Text = AnsiString(OverallDistance);
6401  if(OverallSpeedLimit > -1)
6402  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6403  else
6404  SpeedLimitBox->Text = "Mixed";
6405  // Level2TrackMode = DistanceContinuing;
6406  // SetLevel2TrackMode();
6407  }
6408  else
6409  {
6410  TrackLengthPanel->Visible = true;
6411  TrackLengthPanel->SetFocus();
6412  InfoPanel->Visible = true;
6413  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, need to continue or truncate";
6414  RestoreAllDefaultLengthsButton->Enabled = false;
6415  ResetDefaultLengthButton->Enabled = false;
6416  LengthOKButton->Enabled = false;
6417  // Level2TrackMode = DistanceContinuing;
6418  // SetLevel2TrackMode();
6419  }
6420  }
6421  }
6422  }
6423  else // same as start element
6424  {
6427  SetLevel2TrackMode(54);
6428  Screen->Cursor = TCursor(-2); // Arrow
6429  Utilities->CallLogPop(1713);
6430  return;
6431  }
6433  Screen->Cursor = TCursor(-2); // Arrow
6434  Utilities->CallLogPop(1490);
6435  return;
6436  }
6437 
6438  else if(Level2TrackMode == GapSetting)
6439  {
6440  TrainController->LogEvent("mbLeft + GapSetting");
6442  // HighLightOneGap already called once from SetLevel2TrackMode so have all gap element values set
6443  // & it is highlighted
6444  if(!(Track->FindSetAndDisplayMatchingGap(1, HLoc, VLoc)))
6445  {
6446  Utilities->CallLogPop(50);
6447  return; // true if finds one
6448  }
6449  InfoPanel->Visible = true;
6450  InfoPanel->Caption = "CONNECTING GAPS: Connecting element selected";
6451  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
6452  Delay(0, 500); // 500 msec delay before next selection requested
6453 
6454  // ClearandRebuildRailway(8);//get rid of gap selections
6455  // need to call this later when new gap displayed, else old gap remains
6456 
6457  // now back to highlighting next gap
6458  // bool LocError = false;
6459  if(!(HighLightOneGap(1, HLoc, VLoc)))
6460  {
6461  // all gaps set
6462  ShowMessage("All gaps set");
6463  if(Level2TrackMode == AddTrack)
6464  {
6466  SetLevel1Mode(66);
6467  SetLevel2TrackMode(31);
6468  }
6469  else
6470  {
6472  SetLevel1Mode(37);
6473  }
6474  ClearandRebuildRailway(9); // get rid of last gap ellipse
6475  Utilities->CallLogPop(51);
6476  return;
6477  }
6478  // here if one gap highlighted so return to user to allow corresponding gap to be selected
6479  // by another call to MainScreenMouseDown
6480  }
6481 
6482  else if(Level2TrackMode == AddText)
6483  {
6484  TrainController->LogEvent("mbLeft + AddText");
6486  // X & Y are relative to Display output, but TextBox is placed relative to Form
6487  // if mouse position on first character of an existing piece of text reload it into the editor
6488 
6489  bool TextFoundFlag = false;
6490  int TrueX = 0, TrueY = 0;
6491  AnsiString ExistingText = "";
6493  TFont *ExistingTextFont = new TFont;
6494  int ExistingTextHPos = 0, ExistingTextVPos = 0;
6495  Track->GetTruePositionsFromScreenPos(1, TrueX, TrueY, X, Y);
6496  if(!TextHandler->TextVector.empty())
6497  {
6498  for(TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin(); TextPtr--)
6499  {
6500  if((TrueX >= TextPtr->HPos) && (TrueX < (TextPtr->HPos + abs(TextPtr->Font->Height))) && (TrueY >= TextPtr->VPos) && (TrueY <
6501  (TextPtr->VPos + abs(TextPtr->Font->Height))))
6502  {
6503  ExistingText = TextPtr->TextString;
6504  ExistingTextFont->Assign(TextPtr->Font);
6505  ExistingTextHPos = TextPtr->HPos;
6506  ExistingTextVPos = TextPtr->VPos;
6507  TextFoundFlag = true;
6508  TextHandler->TextErase(9, TrueX, TrueY, ExistingText);
6509  break;
6510  } // if ....
6511  } // for TextPtr...
6512  } // if !TextVector...
6513 
6514  if(TextFoundFlag)
6515  {
6516  TextBox->Left = ExistingTextHPos + Display->Left() - (Display->DisplayOffsetH * 16) - 3;
6517  TextBox->Top = ExistingTextVPos + Display->Top() - (Display->DisplayOffsetV * 16) - 3;
6518  TextBox->Font->Assign(ExistingTextFont);
6519  Display->SetFont(ExistingTextFont);
6520  Text_X = ExistingTextHPos;
6521  Text_Y = ExistingTextVPos;
6522  }
6523  else
6524  {
6525  TextBox->Left = (TextOrUserGraphicGridVal * div((Display->Left() + X), TextOrUserGraphicGridVal).quot) - 3;
6526  TextBox->Top = (TextOrUserGraphicGridVal * div((Display->Top() + Y), TextOrUserGraphicGridVal).quot) - 3;
6527  TextBox->Font->Assign(Display->GetFont());
6528  Text_X = TextOrUserGraphicGridVal * div(NoOffsetX, TextOrUserGraphicGridVal).quot;
6529  Text_Y = TextOrUserGraphicGridVal * div(NoOffsetY, TextOrUserGraphicGridVal).quot;
6530  }
6531  TextBox->Visible = true;
6532  TextBox->SetFocus();
6533  if(TextFoundFlag)
6534  TextBox->Text = ExistingText;
6535  else
6536  TextBox->Text = "New Text: CR=end, ESC=quit";
6537  TextBox->Width = (abs(TextBox->Font->Height) * TextBox->Text.Length() * 0.7);
6538  TextBox->SelectAll();
6539  delete ExistingTextFont;
6540  ClearandRebuildRailway(29); // to remove old text if replaced
6542  Utilities->CallLogPop(1775);
6543  return; // If text input go no further
6544  }
6545 
6547  {
6548  TrainController->LogEvent("mbLeft + MoveTextOrGraphic");
6550  // int HPosInput;// = X + (Display->DisplayOffsetH * 16);
6551  // int VPosInput;// = Y + (Display->DisplayOffsetV * 16);
6552  // Track->GetTruePositionsFromScreenPos(HPosInput, VPosInput, X, Y);
6553  // StartX = X + (Display->DisplayOffsetH * 16);
6554  // StartY = Y + (Display->DisplayOffsetV * 16);
6557  if(!TextFoundFlag) // give precedence to text
6558  {
6560  }
6561  Utilities->CallLogPop(53);
6562  return; // if text move selected don't permit anything else
6563  }
6564 
6565  else if(Level2TrackMode == TrackSelecting)
6566 /* When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
6567  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
6568  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
6569  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
6570  selected rectangle.
6571 */
6572  {
6573  TrainController->LogEvent("mbLeft + TrackSelecting");
6574  ClearandRebuildRailway(10); // to get rid of earlier rectangles
6575  SelectStartPair.first = HLoc;
6576  SelectStartPair.second = VLoc;
6577  }
6578 
6579  else if((Level2TrackMode == CopyMoving) || (Level2TrackMode == CutMoving))
6580 /* The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
6581  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
6582  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
6583  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
6584 */
6585  {
6586  TrainController->LogEvent("mbLeft + CopyMoving or CutMoving");
6588  if((X < ((SelectBitmapHLoc - Display->DisplayOffsetH) * 16) + 4) ||
6589  (X > ((SelectBitmapHLoc + (SelectBitmap->Width / 16) - Display->DisplayOffsetH) * 16) - 4))
6590  {
6591  SelectPickedUp = false;
6592  Utilities->CallLogPop(54);
6593  return; // within 4 pixels of outside of horizontal area (4 pixels are so can't push selection off edge of screen)
6594  }
6595  if((Y < ((SelectBitmapVLoc - Display->DisplayOffsetV) * 16) + 4) ||
6596  (Y > ((SelectBitmapVLoc + (SelectBitmap->Height / 16) - Display->DisplayOffsetV) * 16) - 4))
6597  {
6598  SelectPickedUp = false;
6599  Utilities->CallLogPop(55);
6600  return; // within 4 pixels of outside of vertical area (4 pixels are so can't push selection off edge of screen)
6601  }
6602  else
6603  {
6604  SelectPickedUp = true;
6605  }
6608  }
6609 
6611  {
6612  TrainController->LogEvent("mbLeft + != PrefDirContinuing");
6613  ResetChangedFileDataAndCaption(15, false);
6614 // RlyFile = false; - don't alter this just for PrefDir changes
6615  if(ConstructPrefDir->GetPrefDirStartElement(1, HLoc, VLoc))
6616  {
6620  }
6621  Utilities->CallLogPop(56);
6622  return;
6623  }
6624 
6626  {
6627  TrainController->LogEvent("mbLeft + PrefDirContinuing");
6628  ResetChangedFileDataAndCaption(16, false);
6629 // RlyFile = false; - don't alter this just for PrefDir changes
6630  bool FinishElement;
6631  Screen->Cursor = TCursor(-11); // Hourglass;
6632  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(183, 0).HLoc != HLoc) ||
6633  (ConstructPrefDir->GetFixedPrefDirElementAt(184, 0).VLoc != VLoc))
6634  { // not same as start element
6635  if(ConstructPrefDir->GetNextPrefDirElement(1, HLoc, VLoc, FinishElement))
6636  {
6638  if(FinishElement)
6639  {
6640  ShowMessage("Preferred direction added");
6643  SetLevel1Mode(16);
6644  Screen->Cursor = TCursor(-2); // Arrow
6645  Utilities->CallLogPop(57);
6646  return;
6647  }
6648  else
6649  {
6652  }
6653  // set again since 1st time
6654  // PrefDir vector only had start element & Truncate wasn't enabled, also need
6655  // to do the checks for Loop & End for each element as it is added
6656  }
6657  }
6658  else // same as start element
6659  {
6662  SetLevel1Mode(121);
6663  Screen->Cursor = TCursor(-2); // Arrow
6664  Utilities->CallLogPop(1714);
6665  return;
6666  }
6667  Screen->Cursor = TCursor(-2); // Arrow
6668  Utilities->CallLogPop(58);
6669  return;
6670  }
6671 
6673  {
6674  TrainController->LogEvent("mbLeft + PrefDirSelecting");
6675  ClearandRebuildRailway(56); // to get rid of earlier rectangles
6676  SelectStartPair.first = HLoc;
6677  SelectStartPair.second = VLoc;
6678  }
6679 
6680  else if(Level1Mode == OperMode)
6681  {
6682  if((Level2OperMode == Operating) && CallingOnButton->Down && CallingOnButton->Enabled)
6683  {
6684  TrainController->LogEvent("mbLeft + Operating & CallingOnButton->Down");
6685  int Position;
6686  TTrackElement TrackElement;
6687  if(Track->FindNonPlatformMatch(2, HLoc, VLoc, Position, TrackElement))
6688  {
6689  if(TrackElement.TrackType != SignalPost)
6690  {
6691  CallingOnButton->Down = false;
6692 // InfoPanel->Visible = false; //dropped at v1.3.0, not sure what purpose intended to serve but don't want to lose the info panel as did with this here also added line below to reset
6694  Utilities->CallLogPop(59);
6695  return;
6696  }
6697  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
6698  {
6700  {
6702  x).LeadExitPos] == Position) && (TrackElement.Config[Track->TrackElementAt(429, TrainController->TrainVectorAt(28,
6704  {
6705  // found it!
6706 /*
6707  if(TrackElement.SpeedTag == 68)
6708  {
6709  Display->PlotOutput(0, (HLoc * 16), (VLoc * 16), RailGraphics->bm68CallingOn);
6710  }
6711  if(TrackElement.SpeedTag == 69)
6712  {
6713  Display->PlotOutput(1, (HLoc * 16), (VLoc * 16), RailGraphics->bm69CallingOn);
6714  }
6715  if(TrackElement.SpeedTag == 70)
6716  {
6717  Display->PlotOutput(2, (HLoc * 16), (VLoc * 16), RailGraphics->bm70CallingOn);
6718  }
6719  if(TrackElement.SpeedTag == 71)
6720  {
6721  Display->PlotOutput(3, (HLoc * 16), (VLoc * 16), RailGraphics->bm71CallingOn);
6722  }
6723  if(TrackElement.SpeedTag == 72)
6724  {
6725  Display->PlotOutput(4, (HLoc * 16), (VLoc * 16), RailGraphics->bm72CallingOn);
6726  }
6727  if(TrackElement.SpeedTag == 73)
6728  {
6729  Display->PlotOutput(5, (HLoc * 16), (VLoc * 16), RailGraphics->bm73CallingOn);
6730  }
6731  if(TrackElement.SpeedTag == 74)
6732  {
6733  Display->PlotOutput(6, (HLoc * 16), (VLoc * 16), RailGraphics->bm74CallingOn);
6734  }
6735  if(TrackElement.SpeedTag == 75)
6736  {
6737  Display->PlotOutput(7, (HLoc * 16), (VLoc * 16), RailGraphics->bm75CallingOn);
6738  }
6739 */
6740  Track->TrackElementAt(430, Position).CallingOnSet = true;
6741  Track->PlotSignal(13, Track->TrackElementAt(893, Position), Display);
6742 // added at v 1.3.0 in place of the above to ensure ground signals (as well as others) plot correctly for proceed
6743  // have to call after CallingOnSet becomes true & can't use TrackElement as that still has CallingOnSet false
6744  ClearandRebuildRailway(69); // added at v1.3.0 to replot route on element after PlotSignal above
6747  CallingOnButton->Down = false;
6749 
6750 // set an unrestricted route into the station (just to the first platform) from the stop signal (note that it may be last in an autosigs
6751 // route) but remove any single route elements first (can't reach here if constructing a route), else may try to extend a route that
6752 // has been removed (only a precaution, shouldn't cause any probs whether single route set or not)
6753  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
6754  {
6755  if(AllRoutes->GetFixedRouteAt(192, x).PrefDirSize() == 1)
6756  {
6757  // only allow route element to be removed if not selected for a route start otherwise
6758  // StartSelectionRouteID will be set & will fail at convert
6760  {
6762  AllRoutes->RemoveRouteElement(21, PDE.HLoc, PDE.VLoc, PDE.GetELink());
6763  TrainController->LogEvent("SingleRouteElementRemovedDuringCallon, H = " + AnsiString(PDE.HLoc) + ", V = " +
6764  AnsiString(PDE.VLoc));
6765  }
6766  }
6767  }
6768 
6769 // find the correct entry in CallonVector - i.e. where Position == RouteStartEntry
6770  for(unsigned int x = 0; x < AllRoutes->CallonVector.size(); x++)
6771  {
6772  if(AllRoutes->CallonVector.at(x).RouteStartPosition == Position)
6773  { // found it
6774  if(!(AllRoutes->CallonVector.at(x).RouteOrPartRouteSet))
6775  // if RouteOrPartRouteSet false then set an unrestricted route into platform
6776  {
6777  bool PointsChanged = false;
6778  IDInt ReqPosRouteID(-1);
6779  TOneRoute *NewRoute = new TOneRoute;
6780  bool CallonTrue = true;
6781  if(NewRoute->GetNonPreferredRouteStartElement(1,
6782  Track->TrackElementAt(841, AllRoutes->CallonVector.at(x).RouteStartPosition).HLoc,
6783  Track->TrackElementAt(842, AllRoutes->CallonVector.at(x).RouteStartPosition).VLoc, CallonTrue))
6784  {
6785  if(NewRoute->GetNextNonPreferredRouteElement(1,
6786  Track->TrackElementAt(843, AllRoutes->CallonVector.at(x).PlatformPosition).HLoc,
6787  Track->TrackElementAt(844, AllRoutes->CallonVector.at(x).PlatformPosition).VLoc, CallonTrue, ReqPosRouteID, PointsChanged))
6788  {
6789  if(!PointsChanged) // shouldn't be changed, something wrong if true so don't plot route
6790  {
6791  NewRoute->ConvertAndAddNonPreferredRouteSearchVector(3, ReqPosRouteID);
6792  ClearandRebuildRailway(67); // to plot the route (only finds one so won't call repeatedly)
6793  }
6794  }
6795  }
6796  delete NewRoute;
6797  }
6798  }
6799  }
6800 // InfoPanel->Visible = false;
6801  Utilities->CallLogPop(60);
6802  return;
6803  }
6804  }
6805  }
6806  }
6807  CallingOnButton->Down = false;
6809  Utilities->CallLogPop(61);
6810  return;
6811  }
6812 /* get 1st element, first check if selected points, not in existing route, & in RouteNotStarted mode
6813  if so, set all the flash values, Track->PointFlashFlag & start time, then exit for flasher to take over.
6814  If any of above conditions not met then treat as route selection, setting route flasher if
6815  route continuing.
6816 */
6817 
6818  if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // not 'else if' as both may apply
6819  // disallow route setting if paused
6820  {
6821  if(Level2OperMode == PreStart)
6822  {
6823  PointsFlashDuration = 0.0;
6826  }
6827  else
6828  {
6829  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
6830  if(TTClockSpeed < 1)
6831  TempSpeedVal = TTClockSpeed;
6832  PointsFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
6835  }
6836  if(RouteMode == RouteNotStarted)
6837  {
6838  TrainController->LogEvent("mbLeft + RouteNotStarted");
6839  int Position;
6840  TTrackElement TrackElement;
6841  if(Track->FindNonPlatformMatch(3, HLoc, VLoc, Position, TrackElement))
6842  {
6843  if((TrackElement.TrackType == Points) && !(AllRoutes->TrackIsInARoute(1, Position, 0))
6845  // Flash selected points & changeover if appropriate
6846  // need !Track->PointFlashFlag to prevent another point being selected while another is flashing, & !Track->RouteFlashFlag
6847  // to ensure user only does one thing at a time
6848  {
6849  if(TrackElement.TrainIDOnElement > -1)
6850  {
6851  TrainController->StopTTClockMessage(1, "Can't change points under a train!");
6852  Utilities->CallLogPop(62);
6853  return;
6854  }
6855  PointFlash->SetScreenHVSource(1, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6856 
6857 /*
6858  This used to try to allow any linked trailing edges to cause both points to change, but no good if
6859  there are two adjacent crossovers, where both trailing edges are linked to two different points.
6860  The wrong link might be chosen. Also doubtful if applying a strict order of checks would work, since
6861  may be obscure configurations that would be wrong. This function bypasses the MatchingPoint check, which
6862  ensures that there are no obscure links. Hence better to stick with original.
6863 
6864  //check if trailing edge linked to another point trailing edge
6865  int DivergingPosition = TrackElement.Conn[1];
6866  TTrackElement DivergingElement = Track->TrackElementAt(431, TrackElement.Conn[1]);
6867  DivergingPointVectorPosition = -1;
6868  if((DivergingElement.TrackType == Points) &&
6869  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
6870  {
6871  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
6872  {
6873  ShowMessage("Linked points Locked");
6874  }
6875  else DivergingPointVectorPosition = DivergingPosition;
6876  }
6877  else
6878  {
6879  DivergingPosition = TrackElement.Conn[3];
6880  DivergingElement = Track->TrackElementAt(432, TrackElement.Conn[3]);
6881  if((DivergingElement.TrackType == Points) &&
6882  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
6883  {
6884  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
6885  {
6886  ShowMessage("Linked points locked");
6887  }
6888  else DivergingPointVectorPosition = DivergingPosition;
6889  }
6890  }
6891  Track->PointFlashFlag = true;
6892  PointFlashVectorPosition = Position;
6893  PointFlashStartTime = TrainController->TTClockTime;
6894  [close curly bracket - if include it matches earlier non-commented one!]
6895 */
6896  TTrackElement DivergingElement = Track->TrackElementAt(433, TrackElement.Conn[3]);
6897  int DivergingPosition = TrackElement.Conn[3];
6898  if((DivergingElement.TrackType == Points) && (DivergingElement.Conn[3] == Position) && (Track->MatchingPoint(1, Position,
6899  DivergingPosition))) // full match inc same attributes
6900  {
6901  if(AllRoutes->TrackIsInARoute(4, DivergingPosition, 0))
6902  {
6903  TrainController->StopTTClockMessage(2, "Linked points locked");
6904  }
6905  else
6906  {
6907  Track->PointFlashFlag = true;
6908  PointFlashVectorPosition = Position;
6909  DivergingPointVectorPosition = DivergingPosition;
6911  }
6912  }
6913  else // no matching point, just change this point
6914  {
6915  Track->PointFlashFlag = true;
6916  PointFlashVectorPosition = Position;
6919  }
6920  }
6921 
6922  else if(Track->IsLCAtHV(59, HLoc, VLoc) && !Track->PointFlashFlag && !Track->RouteFlashFlag)//level crossing added at v2.6.0 to allow manual LC changing
6923  {
6924  if(Track->GetInactiveTrackElementFromTrackMap(5, HLoc, VLoc).Attribute != 2) // 2 = LC changing state, can't click if changing
6925  {
6926  Track->LCChangeFlag = true;
6927  bool TrainPresent = false;
6928  if(Track->IsLCBarrierDownAtHV(4, HLoc, VLoc)) //if true then raise barriers
6929  {
6930  //first need to identify the LC in the BarriersDownVector
6931  int BDVectorPos = -1;
6932  if(Track->AnyLinkedBarrierDownVectorManual(1, HLoc, VLoc, BDVectorPos)) //looking for same position & manually closed
6933  { //this largely copied from ClockTimer2
6935  Track->BarriersDownVector.at(BDVectorPos).VLoc, TrainPresent)) //returns true for route or train, and TrainPresent true if train on LC
6936  {
6937  TTrack::TActiveLevelCrossing CLC = Track->BarriersDownVector.at(BDVectorPos);
6938  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
6939  TDateTime TempExcessLCDownTime;
6940  if(Track->BarriersDownVector.at(BDVectorPos).ReducedTimePenalty) //this set in ClockTimer2, relies on train being on LC for >= 1 second or won't
6941  { //get the 3 mins allowance - hard to imagine will pass in less than a second!
6942  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
6943  }
6944  else
6945  {
6946  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
6947  }
6948  if(TempExcessLCDownTime > TDateTime(0))
6949  {
6950  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
6951  }
6952  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
6955  Track->SetLinkedLevelCrossingBarrierAttributes(7, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
6956  Track->ChangingLCVector.push_back(CLC);
6957  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + BDVectorPos);
6958  }
6959  }
6960  }
6961  else //lowering
6962  {
6963  //this largely copied from SetLCChangeValues
6964  TTrack::TActiveLevelCrossing ALC; //constructor sets ReducedTimePenalty to false
6965  ALC.HLoc = HLoc;
6966  ALC.VLoc = VLoc;
6968  ALC.BaseElementSpeedTag = TrackElement.SpeedTag;
6971  ALC.TypeOfRoute = 2;
6972  Track->SetLinkedManualLCs(0, HLoc, VLoc); //this sets all linked LC ConsecSignals values to 2 for manually lowered - differs from SetLCChangeValues which uses the route type
6973  Track->SetLinkedLevelCrossingBarrierAttributes(6, HLoc, VLoc, 2);//set attr to 2 for changing state
6974  Track->ChangingLCVector.push_back(ALC);
6976  {
6977  AnsiString Message = AnsiString("This will open the level crossing manually (it will show in green).\n\nA manually opened"
6978  " level crossing must be manually closed, and as soon as possible to avoid time penalties.\n\n"
6979  "This message will not be shown again.");
6980  TrainController->StopTTClockMessage(93, Message);
6982  }
6983  }
6984  }
6985  }
6986  else // route start
6987  {
6988  if(AutoSigsFlag)
6989  {
6990  AutoRouteStartMarker->SetScreenHVSource(2, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6992  }
6993  else if(PreferredRoute) //added at v2.7.0, was ConsecSignalsRoute
6994  {
6995  SigRouteStartMarker->SetScreenHVSource(3, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6997  }
6998  else
6999  {
7000  NonSigRouteStartMarker->SetScreenHVSource(4, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
7002  }
7003  if(PreferredRoute)
7004  {
7005  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
7006  // another route building
7007  {
7008  ConstructRoute->ClearRoute(); // in case not empty though should be
7010  {
7011  if(AutoSigsFlag)
7013  else
7016  InfoPanel->Visible = true;
7017  if(Level2OperMode == PreStart)
7018  InfoPanel->Caption = "PRE-START: Select next route location";
7019  else
7020  InfoPanel->Caption = "OPERATING: Select next route location";
7021  }
7022  }
7023  Utilities->CallLogPop(63);
7024  return;
7025  }
7026  else // nonpreferred route
7027  {
7028  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
7029  // another route building
7030  {
7031  ConstructRoute->ClearRoute(); // in case not empty though should be
7032  bool CallonFalse = false;
7033  if(ConstructRoute->GetNonPreferredRouteStartElement(0, HLoc, VLoc, CallonFalse))
7034  {
7037  InfoPanel->Visible = true;
7038  if(Level2OperMode == PreStart)
7039  InfoPanel->Caption = "PRE-START: Select next route location";
7040  else
7041  InfoPanel->Caption = "OPERATING: Select next route location";
7042  }
7043  }
7044  Utilities->CallLogPop(64);
7045  return;
7046  } // NonPreferred route
7047  } // TrackType != Points
7048  } // if(Track->FindNonPlatformMatch(HLoc, VLoc, Position, TrackElement))
7049  } // if(RouteMode == RouteNotStarted)
7050  else // RouteContinuing
7051  {
7052  TrainController->LogEvent("mbLeft + RouteContinuing");
7053  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7056  AutoRouteStartMarker->PlotOriginal(14, Display); // if overlay not plotted will ignore
7057  SigRouteStartMarker->PlotOriginal(15, Display); // if overlay not plotted will ignore
7058  NonSigRouteStartMarker->PlotOriginal(16, Display); // if overlay not plotted will ignore
7059  Screen->Cursor = TCursor(-11); // Hourglass - also set to an hourglass when flashing, after found required
7060  // element, but this sets it to an hourglass while searching
7061  bool PointsChanged = false;
7062  if(PreferredRoute)
7063  {
7064  // route added to AllRoutes in GetNextRouteElement if valid
7065  // int ReqPosRouteNumber;
7067  ConstructRoute->ReqPosRouteID, PointsChanged))
7068  {
7069  Track->RouteFlashFlag = true;
7070  PreferredRouteFlag = true;
7071  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7072  if(TTClockSpeed < 1)
7073  TempSpeedVal = TTClockSpeed;
7074  if(Level2OperMode == PreStart)
7075  RouteFlashDuration = 0.0;
7076  else if(PointsChanged)
7077  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7078  else
7079  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
7080  ConstructRoute->SetRouteFlashValues(1, AutoSigsFlag, true); // true for PrefDirRoute
7082  }
7083  else
7084  {
7086  }
7087  Screen->Cursor = TCursor(-2); // Arrow
7088  TrainController->BaseTime = TDateTime::CurrentDateTime();
7090  Utilities->CallLogPop(65);
7091  return;
7092  }
7093  else
7094  {
7095  bool CallonFalse = false;
7097  PointsChanged))
7098  {
7099  Track->RouteFlashFlag = true;
7100  PreferredRouteFlag = false;
7101  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
7102  if(TTClockSpeed < 1)
7103  TempSpeedVal = TTClockSpeed;
7104  if(Level2OperMode == PreStart)
7105  RouteFlashDuration = 0.0;
7106  else if(PointsChanged)
7107  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
7108  else
7109  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
7110  ConstructRoute->SetRouteFlashValues(2, false, false);
7112  }
7113  else
7114  {
7116  }
7117  }
7118  TrainController->BaseTime = TDateTime::CurrentDateTime();
7120  Screen->Cursor = TCursor(-2); // Arrow
7121  }
7122  Utilities->CallLogPop(66);
7123  return;
7124  }
7125  }
7126 
7127  Utilities->CallLogPop(68);
7128  }
7129  catch(const Exception &e)
7130  {
7131  ErrorLog(20, e.Message);
7132  }
7133 }
7134 
7135 // ---------------------------------------------------------------------------
7136 
7137 void TInterface::MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
7138  // ZoomOut mode
7139 {
7140 // NB: DisplayZoomOutOffsetH & V take account of the Min & Max H & V values so don't need these again
7141  try
7142  {
7143  TrainController->LogEvent("MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7144  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) +
7145  "," + AnsiString(Y));
7146  if(Button != mbLeft)
7147  {
7148  // this routine new at v2.1.0. Allows railway moving for zoom-out mode
7151  WholeRailwayMoving = true;
7152  Screen->Cursor = TCursor(-22); // Four arrows;
7153  }
7154  else
7155  {
7156  InfoPanel->Visible = false; // reset infopanel in case not set later
7157  InfoPanel->Caption = "";
7158  int HRounding, VRounding;
7159  int TruePosH = (X / 4) + Display->DisplayZoomOutOffsetH;
7160  int TruePosV = (Y / 4) + Display->DisplayZoomOutOffsetV;
7161  // find nearest screen centre - from 30 to 210 horiz & from 18 to 126 vert
7162  if(TruePosH < 0)
7163  HRounding = -(Utilities->ScreenElementWidth / 4);
7164  else
7165  HRounding = (Utilities->ScreenElementWidth / 4);
7166  int CentreH = (((TruePosH + HRounding) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2));
7167  while((CentreH - Track->GetHLocMax()) >= (Utilities->ScreenElementWidth / 2))
7168  CentreH -= (Utilities->ScreenElementWidth / 2);
7169  while((Track->GetHLocMin() - CentreH) >= (Utilities->ScreenElementWidth / 2))
7170  CentreH += (Utilities->ScreenElementWidth / 2);
7171  if(TruePosV < 0)
7172  VRounding = -(Utilities->ScreenElementHeight / 4);
7173  else
7174  VRounding = (Utilities->ScreenElementHeight / 4);
7175  int CentreV = (((TruePosV + VRounding) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2));
7176  while((CentreV - Track->GetVLocMax()) >= (Utilities->ScreenElementHeight / 2))
7177  CentreV -= (Utilities->ScreenElementHeight / 2);
7178  while((Track->GetVLocMin() - CentreV) >= (Utilities->ScreenElementHeight / 2))
7179  CentreV += (Utilities->ScreenElementHeight / 2);
7180  Display->DisplayOffsetH = CentreH - (Utilities->ScreenElementWidth / 2);
7182 
7183  TLevel2OperMode TempLevel2OperMode = Level2OperMode;
7184  if(Level1Mode == BaseMode)
7185  SetLevel1Mode(17);
7186  else if(Level1Mode == TrackMode)
7187  {
7188  // set edit menu items
7190  PreventGapOffsetResetting = true; // when return from zoom by clicking screen don't force a return to the
7191  // displayed gap, user wants to display the clicked area
7192  SetLevel2TrackMode(32); // revert to earlier track mode from zoom
7193  PreventGapOffsetResetting = false;
7194  }
7195  else if(Level1Mode == PrefDirMode)
7196  {
7198  SetLevel2PrefDirMode(3); // revert to earlier PrefDir mode from zoom
7199  else
7200  SetLevel1Mode(33); // if PrefDirSelecting revert to normap PrefDirMode
7201  }
7202  // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
7203  // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
7204  else if(Level1Mode == TimetableMode)
7205  {
7206  InfoPanel->Visible = false;
7207  }
7208  // Not OperMode or RestartSessionOperMode as that resets the performance file
7209  else if(TempLevel2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
7210  {
7211  OperateButton->Enabled = true;
7212  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
7213  ExitOperationButton->Enabled = true;
7215  }
7216  else if(TempLevel2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
7217  {
7218  OperateButton->Enabled = true;
7219  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
7220  ExitOperationButton->Enabled = true;
7221  TTClockAdjButton->Enabled = true;
7224  }
7225  else if(TempLevel2OperMode == PreStart)
7226  {
7227  OperateButton->Enabled = true;
7228  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
7229  ExitOperationButton->Enabled = true;
7230  TTClockAdjButton->Enabled = true;
7232  }
7233  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
7236  }
7237  Utilities->CallLogPop(69);
7238  }
7239  catch(const Exception &e)
7240  {
7241  ErrorLog(21, e.Message);
7242  }
7243 }
7244 
7245 // ---------------------------------------------------------------------------
7246 
7247 void __fastcall TInterface::MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
7248 {
7249  try
7250  {
7251  // TrainController->LogEvent("MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y)); //dropped at v0.6, too many events
7252  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y));
7253 
7254  if(!mbLeftDown && WholeRailwayMoving) // new at v2.1.0
7255  {
7256  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7258  if(X < 0)
7259  X = 0; // ensure pointer stays within display area
7260  if(X > (MainScreen->Width - 1))
7261  X = MainScreen->Width - 1;
7262  if(Y < 0)
7263  Y = 0;
7264  if(Y > (MainScreen->Height - 1))
7265  Y = MainScreen->Height - 1;
7266 
7267  if(!Display->ZoomOutFlag)
7268  {
7269  int StartOffsetX = (X - StartWholeRailwayMoveHPos) % 16;
7270  int StartOffsetY = (Y - StartWholeRailwayMoveVPos) % 16;
7271  if((abs(X - StartWholeRailwayMoveHPos) >= 16) || (abs(Y - StartWholeRailwayMoveVPos) >= 16))
7272  {
7273  int NewH = X - StartWholeRailwayMoveHPos;
7274  int NewV = Y - StartWholeRailwayMoveVPos;
7275  Display->DisplayOffsetH -= NewH / 16;
7276  Display->DisplayOffsetV -= NewV / 16;
7277  StartWholeRailwayMoveHPos = X - StartOffsetX;
7278  StartWholeRailwayMoveVPos = Y - StartOffsetY;
7281  {
7283  }
7284  }
7285  }
7286 
7287  else
7288  {
7289  int StartZOffsetX = (X - StartWholeRailwayMoveHPos) % 4;
7290  int StartZOffsetY = (Y - StartWholeRailwayMoveVPos) % 4;
7291  if((abs(X - StartWholeRailwayMoveHPos) >= 4) || (abs(Y - StartWholeRailwayMoveVPos) >= 4))
7292  {
7293  int NewH = X - StartWholeRailwayMoveHPos;
7294  int NewV = Y - StartWholeRailwayMoveVPos;
7295  Display->DisplayZoomOutOffsetH -= NewH / 4;
7296  Display->DisplayZoomOutOffsetV -= NewV / 4;
7297  StartWholeRailwayMoveHPos = X - StartZOffsetX;
7298  StartWholeRailwayMoveVPos = Y - StartZOffsetY;
7299  Display->ClearDisplay(10);
7301  }
7302  }
7303  TrainController->BaseTime = TDateTime::CurrentDateTime();
7305  }
7306 
7307  else if(mbLeftDown)
7308  {
7310 /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7311  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7312  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7313  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7314  selected rectangle.
7315  [New] At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7316  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7317  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7318  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7319  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7320  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7321  the selection.
7322 */
7323  {
7324  TrainController->LogEvent("MouseMove + TrackSelecting");
7325  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7326  Track->GetTrackLocsFromScreenPos(2, CurrentHLoc, CurrentVLoc, X, Y);
7327  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7328  // rightmost point and the VLoc value of the bottommost point
7329  if(CurrentHLoc >= StartHLoc)
7330  CurrentHLoc++;
7331  else
7332  StartHLoc++;
7333  if(CurrentVLoc >= StartVLoc)
7334  CurrentVLoc++;
7335  else
7336  StartVLoc++;
7337  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7339  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7341  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7342  CurrentHLoc = Display->DisplayOffsetH;
7343  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7344  CurrentVLoc = Display->DisplayOffsetV;
7345  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7346  ClearandRebuildRailway(14); // to clear earlier rectangles
7347  Display->PlotDashedRect(0, TempRect);
7348  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
7349  }
7350 
7352  {
7353  TrainController->LogEvent("MouseMove + PrefDirSelecting");
7354 
7355  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7356  Track->GetTrackLocsFromScreenPos(5, CurrentHLoc, CurrentVLoc, X, Y);
7357  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7358  // rightmost point and the VLoc value of the bottommost point
7359  if(CurrentHLoc >= StartHLoc)
7360  CurrentHLoc++;
7361  else
7362  StartHLoc++;
7363  if(CurrentVLoc >= StartVLoc)
7364  CurrentVLoc++;
7365  else
7366  StartVLoc++;
7367  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7369  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7371  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7372  CurrentHLoc = Display->DisplayOffsetH;
7373  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7374  CurrentVLoc = Display->DisplayOffsetV;
7375  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7376  ClearandRebuildRailway(57); // to clear earlier rectangles
7377  Display->PlotDashedRect(2, TempRect);
7378  Display->Update(); // need to keep this since Update() not called for PlotSmallOutput as too slow
7379  }
7380 
7382 /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
7383  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
7384  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
7385  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
7386  [New] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
7387  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
7388  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
7389  occupies. Clearand... is called finally to clear earlier selection displays.
7390 */
7391  {
7392  TrainController->LogEvent("MouseMove + Copy or CutMoving & SelectPickedUp");
7393  if(X < 0)
7394  X = 0; // ensure pointer stays within display area
7395  if(X > (MainScreen->Width - 1))
7396  X = MainScreen->Width - 1;
7397  if(Y < 0)
7398  Y = 0;
7399  if(Y > (MainScreen->Height - 1))
7400  Y = MainScreen->Height - 1;
7403  ClearandRebuildRailway(15); // plots SelectBitmap at the position given by NewSelectBitmapHLoc & ...VLoc
7404  }
7405 
7407  {
7408  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & TextFoundFlag");
7410  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7412  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7413 
7414  TextHandler->TextPtrAt(26, TextItem)->HPos = NewHPos;
7415  TextHandler->TextPtrAt(27, TextItem)->VPos = NewVPos;
7417  }
7418 
7420  {
7421  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & UserGraphicFoundFlag");
7423  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7425  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7426 
7430  }
7431  }
7432  Utilities->CallLogPop(70);
7433  }
7434  catch(const Exception &e)
7435  {
7436  ErrorLog(22, e.Message);
7437  }
7438 }
7439 
7440 // ---------------------------------------------------------------------------
7441 void __fastcall TInterface::MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
7442 {
7443 /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7444  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7445  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7446  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7447  selected rectangle.
7448  [Repeated from MouseMove] - At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7449  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7450  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7451  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7452  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7453  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7454  the selection.
7455  [New] This function can take some time so an houglass cursor is displayed. The rectangle is fully defined, so the final screen X & Y
7456  values are translated into HLoc & VLoc values (wrt whole railway) and SelectEndPair set using them. The rectangle can be defined in any
7457  direction, so the end points may be before or after the starting points for both horizontal and vertical directions. Therefore the
7458  rectangle that will be used subsequently - SelectRect - is defined from SelectStart and SelectEnd allowing for any direction. Screen
7459  limits are set as during MouseMove, and a dashed edge drawn as before. Then a check is made to see if the final rectangle has any area,
7460  and if not 'Select' mode is kept and the function ends so that a new rectangle can be drawn, otherwise new menu items Cut, Copy & Delete,
7461  are enabled. Now the SelectBitmap is made ready by filling with white prior to the track bitmaps being copied. If this isn't done the
7462  track bitmaps are loaded from the top left hand corner and the rest becomes black - not what is wanted! The SelectVector (defined in
7463  TrackUnit) is then loaded with the elements enclosed by the rectangle, top to bottom and left to right, active track elements first then
7464  inactive track elements. Empty squares are ignored as are default (erased) elements. Now the SelectVector is read and the corresponding
7465  element bitmaps transferred to SelectBitmap in the appropriate positions, then a dashed border added. Finally the cursor is changed back
7466  to an arrow.
7467 */
7468  try
7469  {
7470  TrainController->LogEvent("MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7471  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7472  WholeRailwayMoving = false; // added at v2.1.0
7473  Screen->Cursor = TCursor(-2); // Arrow; (to reset from four arrows when moving) added at v2.1.0
7475  {
7476  TrainController->LogEvent("MouseUp + TrackSelecting + mbLeftDown");
7477  Screen->Cursor = TCursor(-11); // Hourglass;
7478  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7479  Track->GetTrackLocsFromScreenPos(3, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
7480 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7481 // rightmost point and the VLoc value of the bottommost point
7482  if(EndHLoc >= StartHLoc)
7483  EndHLoc++;
7484  else
7485  StartHLoc++;
7486  if(EndVLoc >= StartVLoc)
7487  EndVLoc++;
7488  else
7489  StartVLoc++;
7490  if(StartHLoc >= EndHLoc)
7491  {
7492  SelectRect.left = EndHLoc;
7493  SelectRect.right = StartHLoc;
7494  }
7495  else
7496  {
7497  SelectRect.left = StartHLoc;
7498  SelectRect.right = EndHLoc;
7499  }
7500  if(StartVLoc >= EndVLoc)
7501  {
7502  SelectRect.top = EndVLoc;
7503  SelectRect.bottom = StartVLoc;
7504  }
7505  else
7506  {
7507  SelectRect.top = StartVLoc;
7508  SelectRect.bottom = EndVLoc;
7509  }
7514  if(SelectRect.left - Display->DisplayOffsetH < 0)
7516  if(SelectRect.top - Display->DisplayOffsetV < 0)
7521  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
7522  {
7523  SelectionValid = false;
7525  mbLeftDown = false;
7526  Screen->Cursor = TCursor(-2); // Arrow;
7527  Utilities->CallLogPop(71);
7528  return; // no rectangle
7529  }
7530  else
7531  {
7532  ReselectMenuItem->Enabled = false;
7533  CutMenuItem->Enabled = true;
7534  CopyMenuItem->Enabled = true;
7535  FlipMenuItem->Enabled = true;
7536  MirrorMenuItem->Enabled = true;
7537  RotRightMenuItem->Enabled = true;
7538  RotLeftMenuItem->Enabled = true;
7539  RotateMenuItem->Enabled = true;
7540  PasteMenuItem->Enabled = false;
7541 // PasteWithAttributesMenuItem->Enabled = false; //new menu item for v2.2.0 only enabled after cutting
7542  DeleteMenuItem->Enabled = true;
7543  if(Track->IsTrackFinished())
7544  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
7545  else
7546  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
7547  SelectBiDirPrefDirsMenuItem->Visible = false;
7548  CancelSelectionMenuItem->Enabled = true;
7549  // set SelectBitmap
7550  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
7551  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
7552 
7553  // fill it with transparent white (i.e. use Draw) else graphics all plot from top left hand corner
7554  for(int H = 0; H < (SelectBitmap->Width) / 16; H++)
7555  {
7556  for(int V = 0; V < (SelectBitmap->Height) / 16; V++)
7557  {
7558  SelectBitmap->Canvas->Draw(H * 16, V * 16, RailGraphics->bmSolidBgnd);
7559  // NB in above if use bmTransparent it ISN'T transparent, but if use the non-transparent bmSolidBgnd it IS transparent
7560  // presumably superimposing a transparent bitmap onto a transparent bitmap makes the result non-transparent!
7561  }
7562  }
7563 
7564  // store elements in Track->SelectVector, active elements first then inactive so active element plotted first during paste
7565  // clear the vector first
7567  TTrackElement TempElement; // default element
7568  bool FoundFlag;
7569  for(int x = SelectRect.left; x < SelectRect.right; x++)
7570  {
7571  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7572  {
7573  int ATVecPos = Track->GetVectorPositionFromTrackMap(2, x, y, FoundFlag);
7574  if(FoundFlag)
7575  {
7576  TempElement = Track->TrackElementAt(440, ATVecPos);
7577  if(TempElement.SpeedTag > 0)
7578  Track->SelectPush(TempElement); // don't store erase elements
7579  }
7580  }
7581  }
7582  // now store inactive elements
7583  for(int x = SelectRect.left; x < SelectRect.right; x++)
7584  {
7585  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7586  {
7587  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(2, x, y, FoundFlag);
7588  if(FoundFlag)
7589  {
7590  TempElement = Track->InactiveTrackElementAt(30, IATVecPair.first);
7591  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
7592  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
7593  {
7594  TempElement = Track->InactiveTrackElementAt(31, IATVecPair.second);
7595  Track->SelectPush(TempElement);
7596  }
7597  }
7598  }
7599  }
7600  // store text items
7601  int LowSelectHPos = SelectRect.left * 16;
7602  int HighSelectHPos = SelectRect.right * 16;
7603  int LowSelectVPos = SelectRect.top * 16;
7604  int HighSelectVPos = SelectRect.bottom * 16;
7605  TextHandler->SelectTextVector.clear();
7606  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
7607  {
7608  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
7609  {
7610  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
7611  HighSelectVPos))
7612  {
7613  // have to create a new TextItem in order to create a new Font object
7614  // BUT: only create new items where they don't appear as named location names
7615  // in SelectVector, since those names shouldn't be copied or pasted.
7616  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
7617  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
7618  bool SelectVectorNamedElement = false;
7619  AnsiString SelectTextString; // new at v2.2.0
7620  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
7621  {
7622  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
7623  {
7624  SelectVectorNamedElement = true;
7625  break;
7626  }
7627  }
7628  if(SelectVectorNamedElement) // changed at v2.2.0
7629  {
7630  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
7631  }
7632  else // new at v2.2.0
7633  {
7634  SelectTextString = TextPtr->TextString;
7635  }
7636  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
7637  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
7638  }
7639  }
7640  }
7641  // store graphic items, but first clear SelectGraphicVector
7642  Track->SelectGraphicVector.clear();
7643  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
7644  {
7645  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
7646  UserGraphicPtr++)
7647  {
7648  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) &&
7649  (UserGraphicPtr->VPos >= LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
7650  {
7651  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
7652  }
7653  }
7654  }
7655 // new method - direct copying of existing selection so text included
7656  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
7657  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
7658  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
7659  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
7660  SelectionValid = true;
7661  }
7662  Screen->Cursor = TCursor(-2); // Arrow;
7663  }
7664 
7666  {
7667  TrainController->LogEvent("MouseUp + PrefDirSelecting + mbLeftDown");
7668  Screen->Cursor = TCursor(-11); // Hourglass;
7669 
7670  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7671  Track->GetTrackLocsFromScreenPos(6, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
7672 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7673 // rightmost point and the VLoc value of the bottommost point
7674  if(EndHLoc >= StartHLoc)
7675  EndHLoc++;
7676  else
7677  StartHLoc++;
7678  if(EndVLoc >= StartVLoc)
7679  EndVLoc++;
7680  else
7681  StartVLoc++;
7682  if(StartHLoc >= EndHLoc)
7683  {
7684  SelectRect.left = EndHLoc;
7685  SelectRect.right = StartHLoc;
7686  }
7687  else
7688  {
7689  SelectRect.left = StartHLoc;
7690  SelectRect.right = EndHLoc;
7691  }
7692  if(StartVLoc >= EndVLoc)
7693  {
7694  SelectRect.top = EndVLoc;
7695  SelectRect.bottom = StartVLoc;
7696  }
7697  else
7698  {
7699  SelectRect.top = StartVLoc;
7700  SelectRect.bottom = EndVLoc;
7701  }
7706  if(SelectRect.left - Display->DisplayOffsetH < 0)
7708  if(SelectRect.top - Display->DisplayOffsetV < 0)
7713  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
7714  {
7716  mbLeftDown = false;
7717  Screen->Cursor = TCursor(-2); // Arrow;
7718  Utilities->CallLogPop(1551);
7719  return; // no rectangle
7720  }
7721  else
7722  {
7723  SelectBiDirPrefDirsMenuItem->Enabled = true;
7724  CancelSelectionMenuItem->Enabled = true;
7725  // don't need SelectBitmap for PrefDir selection
7726 
7727  // store active elements in Track->SelectVector, ignore inactive elements
7728  // clear the vector first
7730  TTrackElement TempElement; // default element
7731  bool FoundFlag;
7732  for(int x = SelectRect.left; x < SelectRect.right; x++)
7733  {
7734  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7735  {
7736  int ATVecPos = Track->GetVectorPositionFromTrackMap(43, x, y, FoundFlag);
7737  if(FoundFlag)
7738  {
7739  TempElement = Track->TrackElementAt(729, ATVecPos);
7740  if(TempElement.SpeedTag > 0)
7741  Track->SelectPush(TempElement); // don't store erase elements
7742  }
7743  }
7744  }
7745  }
7746  Screen->Cursor = TCursor(-2); // Arrow;
7747  }
7748 
7750 /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
7751  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
7752  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
7753  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
7754  [Repeated from MouseMove] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
7755  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
7756  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
7757  occupies. Clearand... is called finally to clear earlier selection displays.
7758  [New] - The only action here is to transfer the values of NewSelectBitmapHLoc & VLoc to SelectBitmapHLoc & VLoc so that the selection
7759  stays in the same position (Clearand... checks whether the mouse is moving (both mbLeftDown & SelectPickedUp true) or stopped (either
7760  mbLeftDown or SelectPickedUp false) and uses NewSelectBitmapHLoc & VLoc or SelectBitmapHLoc & SelectBitmapVLoc respectively.
7761 */
7762  {
7763  TrainController->LogEvent("MouseUp + Copy or CutMoving + mbLeftDown + SelectPickedUp");
7766  }
7767 
7768  mbLeftDown = false;
7769  Track->CalcHLocMinEtc(11);
7770  Utilities->CallLogPop(72);
7771  }
7772  catch(const Exception &e)
7773  {
7774  ErrorLog(23, e.Message);
7775  }
7776 }
7777 
7778 // ---------------------------------------------------------------------------
7779 
7780 void __fastcall TInterface::MasterClockTimer(TObject *Sender)
7781 {
7782  try
7783  {
7784  // don't call LogEvent here as would occur too often
7785  // have to allow in zoomout mode
7786  if(ErrorLogCalledFlag)
7787  return; // don't continue after an error
7788 
7789  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MasterClockTimer");
7790  // put counter outside Clock2 as that may be missed
7791  LCResetCounter++;
7792 // this checks LCs every 20 clock ticks (1 sec) & raises barriers if no route & no train present, to avoid delays due to too frequent calls
7793  if(LCResetCounter > 19)
7794  LCResetCounter = 0;
7796  if(WarningFlashCount > 4)
7797  WarningFlashCount = 0;
7798  if(WarningFlashCount == 0)
7799  {
7801  }
7802 
7803  if(Utilities->CallLog.size() > 50) // use CTRL ALT 2 to see CallLogSize as program operates
7804  {
7805  throw Exception("Warning - Utilities->CallLog contains more than 50 items"); // check before clock stopped
7806  }
7807 
7809  // stopped during 'Paused', when modal windows appear - Popup menu & ShowMessage, and at other times
7810  {
7811  // RestartTime is TTClockTime when operation pauses (timetable start time initially),
7812  // BaseTime is CurrentDateTime() when operation restarts
7813 
7814 // clock speed multiplier
7815  double RealTimeDouble = double(TDateTime::CurrentDateTime() - TrainController->BaseTime);
7816  TrainController->TTClockTime = TDateTime(TTClockSpeed * RealTimeDouble) + TrainController->RestartTime;
7817 // TrainController->TTClockTime = TDateTime::CurrentDateTime() - TrainController->BaseTime + TrainController->RestartTime;
7818  }
7819 
7820  TotalTicks++;
7822  {
7823  MissedTicks++;
7824  Utilities->CallLogPop(774);
7825  return;
7826  }
7827  Utilities->Clock2Stopped = true; //don't allow overlapping calls
7828  ClockTimer2(0);
7829  Utilities->Clock2Stopped = false;
7830  Utilities->CallLogPop(73);
7831  }
7832  catch(const Exception &e)
7833  {
7834  ErrorLog(24, e.Message);
7835  }
7836 }
7837 
7838 // ---------------------------------------------------------------------------
7839 
7840 void TInterface::ClockTimer2(int Caller)
7841 {
7842 // called every 50mSec
7843  try
7844  {
7845  // have to allow in zoomout mode
7846  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClockTimer2");
7847 
7848  // dropped at 2.0.0 because RestoreFocusPanel->SetFocus(); hides the help screen
7849  // If a button holds focus then all that is needed is to click the screen and the arrow keys work correctly
7850 
7851 /* Dropped when new .chm help file introduced at v2.0.0 - this hid it after ~20ms. Replaced by a new section in
7852  MainScreenMouseDown where focus restored to screen when click anywhere on screen, allowing navigation keys to
7853  move screen when clicked if focus had been captured by another panel when these keys just cycle through the panel buttons
7854 
7855  bool FocusRestoreAllowedFlag = true; //added at v1.3.0
7856 
7857  if(TextBox->Focused() || DistanceBox->Focused() || SpeedLimitBox->Focused() || LocationNameTextBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() ||
7858  SpeedEditBox2->Focused() || LocationNameComboBox->Focused() || AddSubMinsBox->Focused() || SpeedEditBox->Focused() || PowerEditBox->Focused() || OneEntryTimetableMemo->Focused() ||
7859  AddPrefDirButton->Focused()) //Added at v1.3.0. If any of these has focus then they keep it until they release it. AddPrefDirButton is included as it should keep focus
7860  FocusRestoreAllowedFlag = false; //when it has it - eases the setting of PrefDirs, also this button becomes disabled after use so focus returns to Interface naturally
7861 
7862  if(!Focused() && FocusRestoreAllowedFlag && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0)) //condition added at v1.3.0 to ensure focus returned to
7863  //Interface (so arrow keys work to move screen) & not left at any of the buttons or other Windows controls
7864  //include the Windows API functions to test that the mouse buttons are not down (strictly only need left but user may have mapped the left onto the right so test both) - if not
7865  //tested then don't always respond to button clicks on navigation and other buttons because the focus can be grabbed back from the button by RestoreFocusPanel before the button
7866  //can respond (takes about 200mSec from click to response) a delay is also included to doubly avoid the button losing focus as above
7867  {
7868  ClockTimer2Count++; //doesn't matter what value it starts at on first use, it will soon revert to 0
7869  if(ClockTimer2Count > 10) ClockTimer2Count = 0; //half second delay
7870  if(ClockTimer2Count == 0)
7871  {
7872  RestoreFocusPanel->Visible = true;
7873  RestoreFocusPanel->Enabled = true;
7874  RestoreFocusPanel->BringToFront();
7875  //RestoreFocusPanel->SetFocus(); //to remove focus from anything else
7876  RestoreFocusPanel->Enabled = false; //to remove focus from RestoreFocusPanel & return it to Interface
7877  RestoreFocusPanel->Visible = false;
7878  }
7879  }
7880  else ClockTimer2Count = 0; //reset to 0 so ensure full delay occurs before RestoreFocusPanel grabs focus from anything else
7881 */
7882 
7883  CallLogTickerLabel->Caption = Utilities->CallLog.size(); // diagnostic test function to ensure all CallLogs are popped - visibility
7884  // toggled by 'Ctrl Alt 2' when Interface form has focus
7885 
7886  // set current time
7887  TDateTime Now = TrainController->TTClockTime;
7888 
7889  if(!OAListBox->MouseInClient) //added at v2.7.0 to reset this flag whenever mouse not in OAListBox
7890  {
7892  }
7893 
7898 
7899  if(OperatorActionPanel->Visible)
7903  TrainController->OpActionPanelHintDelayCounter = 60; // new at v2.2.0
7904 
7905  TrainController->RandomFailureCounter++; // new at v2.4.0 counts up for 53 seconds then resets
7907  {
7909  }
7910 
7911 // Update Displayed Clock - resets to 0 at 96hours
7913 
7914 // Below added at v2.1.0 to ensure WholeRailwayMoving flag reset when not moving (when rh mouse button up) as sometimes misses
7915 // MouseUp events, probably due to a clash between a moving event and a mouse up event. Note that checks that both mouse buttons are up because
7916 // function only checks the physical buttons, not the logical buttons. Most sig bit of return value set form key down.
7917  if(WholeRailwayMoving && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0))
7918  {
7919  WholeRailwayMoving = false;
7920  Screen->Cursor = TCursor(-2); // Arrow
7921  }
7922 
7923 // save session if required
7924  if(SaveSessionFlag)
7925  {
7926  SaveSession(0);
7927  SaveSessionFlag = false;
7928  }
7929 // load session if required
7930  if(LoadSessionFlag)
7931  {
7932  if(ClearEverything(3))
7933  {
7934  LoadSession(0);
7935  }
7936  LoadSessionFlag = false;
7937  }
7938 
7939 // check if any LCs need barriers raising
7940 
7942  {
7944  {
7945  for(int x = Track->BarriersDownVector.size() - 1; x >= 0; x--) //iterate downwards because erase element
7946  {
7947  bool TrainPresent = false;
7949  TrainPresent)) //returns true for route or train, and TrainPresent true if train on LC
7950  {
7951  if(TrainPresent)
7952  {
7953  Track->BarriersDownVector.at(x).ReducedTimePenalty = true; //to allow 3 mins before time penalty starts to clock up, if no train passes then no time allowance
7954  }
7955  }
7956  else
7957  {
7958  if(Track->BarriersDownVector.at(x).TypeOfRoute != 2) //added at v2.6.0 for manual LC operation
7959  {
7960  Track->LCChangeFlag = true;
7962  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
7963  TDateTime TempExcessLCDownTime;
7964  if(Track->BarriersDownVector.at(x).ReducedTimePenalty)
7965  {
7966  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
7967  }
7968  else
7969  {
7970  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
7971  }
7972  if(TempExcessLCDownTime > TDateTime(0))
7973  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
7974 
7975  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
7978  Track->SetLinkedLevelCrossingBarrierAttributes(0, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
7979  Track->ChangingLCVector.push_back(CLC);
7980  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + x);
7981  }
7982  }
7983  }
7984  }
7985  }
7986 // clear LCChangeFlag if no LCs changing
7987  if(Track->ChangingLCVector.empty())
7988  {
7989  Track->LCChangeFlag = false;
7990  }
7991 
7992 // remove any single route elements if operating, but only if not constructing a route, else if extending the single route
7993 // element it may be removed prior to conversion & cause an error
7994 
7995 // note that if a train enters at a continuation and a signal is next but one to the continuation then the route element at that
7996 // signal won't be removed because the train's LagElement is still -1 and trains only remove route elements when LagElement is > -1.
7997 // This also means that a preferred route can't be cancelled as it's under a train, but it's probably not worth adding a patch just for
7998 // this, it shouldn't interfere with operation.
8000  {
8001  bool ElementRemovedFlag = false; // introduced at v0.6 to avoid calling Clearand.... multiple times
8002  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
8003  {
8004  if(AllRoutes->GetFixedRouteAt(187, x).PrefDirSize() == 1)
8005  {
8006  // only allow route element to be removed if not selected for a route start otherwise StartSelectionRouteID will be
8007  // set & will fail at convert
8009  {
8011  //also don't remove if it links two automatic signal routes (reported by Daniel Gill for Darlington via discord on 13/12/20)
8012  //added at v2.6.1
8013  //note that a train will still remove the route element when it reaches it because of the 3rd condition below, but it will be removed when the train
8014  //is half on the preceding element rather than fully on it, in other cases the train has to be fully on the element because the route only becomes a
8015  //single element at that stage
8016  unsigned int LinkFromTVNumber = Track->TrackElementAt(1007, PDE.GetTrackVectorPosition()).Conn[PDE.GetELinkPos()];
8017  unsigned int LinkToTVNumber = Track->TrackElementAt(1008, PDE.GetTrackVectorPosition()).Conn[PDE.GetXLinkPos()];
8018  int RouteNumber1, RouteNumber2, TrainID; //not used
8019  if((AllRoutes->GetRouteTypeAndNumber(37, LinkFromTVNumber, PDE.GetELinkPos(), RouteNumber1) != TAllRoutes::AutoSigsRoute) ||
8020  (AllRoutes->GetRouteTypeAndNumber(38, LinkToTVNumber, PDE.GetXLinkPos(), RouteNumber2) != TAllRoutes::AutoSigsRoute) ||
8021  (Track->TrackElementAt(1009, LinkFromTVNumber).TrainIDOnElement > -1)) //don't need to test for it being a bridge as then LinkFromTVNumber can't be
8022  //an autosigs route
8023  {
8024  AllRoutes->RemoveRouteElement(20, PDE.HLoc, PDE.VLoc, PDE.GetELink());
8025  ElementRemovedFlag = true;
8026  TrainController->LogEvent("SingleRouteElementRemoved, H = " + AnsiString(PDE.HLoc) + ", V = " + AnsiString(PDE.VLoc));
8027  }
8028  }
8029  }
8030  }
8031  if(!Display->ZoomOutFlag && ElementRemovedFlag)
8032  {
8034  }
8035  // if zoomed out ignore, will display correctly when zoom in
8036  // if leave the Zoomout condition out then the zoom out will spontaneously cancel and the track won't display because
8037  // PlotOutput returns if zoomed out, and the zoom out flag isn't reset until the end of Clearand.....
8038  // this was moved outside the for.. next.. loop in v0.6 as it could be called multiple times and slowed down operation (noticeable with a fast clock)
8039  }
8040 // stop clock if hover over a warning
8041  bool WH1 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog1->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog1->Width + OutputLog1->Left))
8042  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog1->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog1->Height + OutputLog1->Top))
8043  && OutputLog1->Caption != "";
8044  bool WH2 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog2->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog2->Width + OutputLog2->Left))
8045  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog2->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog2->Height + OutputLog2->Top))
8046  && OutputLog2->Caption != "";
8047  bool WH3 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog3->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog3->Width + OutputLog3->Left))
8048  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog3->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog3->Height + OutputLog3->Top))
8049  && OutputLog3->Caption != "";
8050  bool WH4 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog4->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog4->Width + OutputLog4->Left))
8051  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog4->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog4->Height + OutputLog4->Top))
8052  && OutputLog4->Caption != "";
8053  bool WH5 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog5->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog5->Width + OutputLog5->Left))
8054  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog5->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog5->Height + OutputLog5->Top))
8055  && OutputLog5->Caption != "";
8056  bool WH6 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog6->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog6->Width + OutputLog6->Left))
8057  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog6->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog6->Height + OutputLog6->Top))
8058  && OutputLog6->Caption != "";
8059  bool WH7 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog7->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog7->Width + OutputLog7->Left))
8060  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog7->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog7->Height + OutputLog7->Top))
8061  && OutputLog7->Caption != "";
8062  bool WH8 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog8->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog8->Width + OutputLog8->Left))
8063  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog8->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog8->Height + OutputLog8->Top))
8064  && OutputLog8->Caption != "";
8065  bool WH9 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog9->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog9->Width + OutputLog9->Left))
8066  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog9->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog9->Height + OutputLog9->Top))
8067  && OutputLog9->Caption != "";
8068  bool WH10 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog10->Left) &&
8069  (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog10->Width + OutputLog10->Left)) && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog10->Top) &&
8070  (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog10->Height + OutputLog10->Top)) && OutputLog10->Caption != "";
8071 
8072  if(WH1 || WH2 || WH3 || WH4 || WH5 || WH6 || WH7 || WH8 || WH9 || WH10)
8073  {
8074  if(!WarningHover)
8075  {
8076  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
8078  WarningHover = true;
8079  }
8080  }
8081  else if(WarningHover)
8082  {
8083  WarningHover = false;
8084  TrainController->BaseTime = TDateTime::CurrentDateTime();
8086  }
8087 
8088 // development panel - visibility toggled by 'Ctrl Alt 3' when Interface form has focus
8089  if(DevelopmentPanel->Visible)
8090  {
8091  int Position;
8092  TTrackElement TrackElement;
8093  AnsiString Type[15] =
8094  {"Simple", "Crossover", "Points", "Buffers", "Bridge", "SignalPost", "Continuation", "Platform", "GapJump", "FootCrossing", "Unused", "Concourse",
8095  "Parapet", "NamedNonStationLocation", "Erase"};
8096 
8097  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
8098  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
8099  int HLoc, VLoc;
8100  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
8101  DevelopmentPanel->Caption = CurDir + " " + MouseStr;
8102  Track->GetTrackLocsFromScreenPos(7, HLoc, VLoc, ScreenX, ScreenY);
8103  if(Track->FindNonPlatformMatch(1, HLoc, VLoc, Position, TrackElement))
8104  {
8105  DevelopmentPanel->Caption = MouseStr + "; TVPos: " + AnsiString(Position) + "; H: " + AnsiString(HLoc) + "; V: " + AnsiString(VLoc) +
8106  "; SpTg: " + AnsiString(TrackElement.SpeedTag) + "; Type: " + Type[TrackElement.TrackType] + "; Att: " + AnsiString(TrackElement.Attribute)
8107  + "; TrID: " + AnsiString(TrackElement.TrainIDOnElement) + "; TrID01: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos01) +
8108  "; TrID23: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos23) + "; " + TrackElement.LocationName + "; " +
8109  TrackElement.ActiveTrackElementName;
8110 // + "; OAHintCtr: " + TrainController->OpActionPanelHintDelayCounter;
8111  }
8112  }
8113 
8114  if(Level1Mode == TimetableMode)
8115  {
8116 /*These are for Shift Key shortcuts. Unless 'Click()' execution occurs after the key is pressed Windows stores the key until after any code is executed then selects
8117 the timetable entry that begins with the letter corresponding to the key. See DevHistory.txt for the version after v2.4.3 for details.
8118 
8119 First make sure the selected entry is the Highlighted entry, but only if both mouse buttons are up, to make sure AllEntriesTTListBoxMouseUp runs first or TopIndex
8120 likely to be set to the wrong position since when ...Selected... runs it sets TopIndex accordingly. Then when ...MouseUp runs it will use the wrong value and select
8121 the entry that the mouse is now on rather than the one that was chosen.
8122 Later addition: Set member variable AllEntriesTTListBox->TopIndex here if any flag set so when Copy or any other key function runs the top index is correct
8123 */
8124  if((GetKeyState(VK_LBUTTON) >= 0) && (GetKeyState(VK_RBUTTON) >= 0) && (TTCurrentEntryPtr > 0)) //high order bit set to 1 when button down, so arithmetically it is negative
8125  { //TTCurrentEntryPtr == 0 when create a timetable
8126  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
8127  }
8128  if(AnyTTKeyFlagSet()) //true if any of the below flags set
8129  {
8130  AllEntriesTTListBox->TopIndex = AllEntriesTTListBoxTopPosition; //reset it to the value before the key press changes it (see FormKeyDown)
8131  }
8133  {
8134  PreviousTTEntryButton->Click();
8135  SetTopIndex(0);
8136  PreviousTTEntryKeyFlag = false;
8137  }
8138  else if(NextTTEntryKeyFlag)
8139  {
8140  NextTTEntryButton->Click();
8141  SetTopIndex(1);
8142  NextTTEntryKeyFlag = false;
8143  }
8144  else if(MoveTTEntryUpKeyFlag)
8145  {
8146  MoveTTEntryUpButton->Click();
8147  SetTopIndex(2);
8148  MoveTTEntryUpKeyFlag = false;
8149  }
8150  else if(MoveTTEntryDownKeyFlag)
8151  {
8152  MoveTTEntryDownButton->Click();
8153  SetTopIndex(3);
8154  MoveTTEntryDownKeyFlag = false;
8155  }
8156  else if(CopyTTEntryKeyFlag)
8157  {
8158  CopyTTEntryButton->Click();
8159  SetTopIndex(4);
8160  CopyTTEntryKeyFlag = false;
8161  }
8162  else if(CutTTEntryKeyFlag)
8163  {
8164  CutTTEntryButton->Click();
8165  SetTopIndex(5);
8166  CutTTEntryKeyFlag = false;
8167  }
8168  else if(PasteTTEntryKeyFlag)
8169  {
8170  PasteTTEntryButton->Click();
8171  SetTopIndex(6);
8172  PasteTTEntryKeyFlag = false;
8173  }
8174  else if(DeleteTTEntryKeyFlag)
8175  {
8176  DeleteTTEntryButton->Click();
8177  SetTopIndex(7);
8178  DeleteTTEntryKeyFlag = false;
8179  }
8180  else if(NewTTEntryKeyFlag)
8181  {
8182  NewTTEntryButton->Click();
8183  SetTopIndex(8);
8184  NewTTEntryKeyFlag = false;
8185  }
8186  else if(AZOrderKeyFlag)
8187  {
8188  AZOrderButton->Click();
8189  SetTopIndex(9);
8190  AZOrderKeyFlag = false;
8191  }
8193  {
8194  TTServiceSyntaxCheckButton->Click();
8195  SetTopIndex(12);
8197  }
8198  else if(ValidateTimetableKeyFlag)
8199  {
8200  ValidateTimetableButton->Click();
8201  SetTopIndex(13);
8202  ValidateTimetableKeyFlag = false;
8203  }
8204  else if(SaveTTKeyFlag)
8205  {
8206  SaveTTButton->Click();
8207  SetTopIndex(14);
8208  SaveTTKeyFlag = false;
8209  }
8210  else if(SaveTTAsKeyFlag)
8211  {
8212  SaveTTAsButton->Click();
8213  SetTopIndex(15);
8214  SaveTTAsKeyFlag = false;
8215  }
8216  else if(RestoreTTKeyFlag)
8217  {
8218  RestoreTTButton->Click();
8219  SetTopIndex(16);
8220  RestoreTTKeyFlag = false;
8221  }
8222  else if(ExportTTKeyFlag)
8223  {
8224  ExportTTButton->Click();
8225  SetTopIndex(17);
8226  ExportTTKeyFlag = false;
8227  }
8228  else if(ConflictAnalysisKeyFlag)
8229  {
8230  ConflictAnalysisButton->Click();
8231  SetTopIndex(18);
8232  ConflictAnalysisKeyFlag = false;
8233  }
8234 
8235 
8236 // highlight timetable entry if in tt mode (have to call this regularly so will scroll with the listbox)
8237  if(!TimetableEditVector.empty() && (TTCurrentEntryPtr > 0))
8238  {
8240  }
8241  else
8242  {
8244  }
8245  }
8246 
8247 // set cursor
8249  {
8250  if(!TempCursorSet)
8251  {
8252  TempCursor = Screen->Cursor;
8253  TempCursorSet = true;
8254  }
8255  Screen->Cursor = TCursor(-11); // Hourglass
8256  }
8257  else
8258  {
8259  if(TempCursorSet)
8260  {
8261  Screen->Cursor = TempCursor;
8262  TempCursorSet = false;
8263  }
8264  }
8265 
8266  if(Level2OperMode == Operating)
8267  {
8268  TrainController->Operate(0); // ensure this called AFTER the single element route removal to ensure any single elements removed
8269  // prior to CallingOnAllowed being called (in UpdateTrain) as that sets a route from the stop signal
8271  {
8272  UpdateOperatorActionPanel(0); // new at v2.2.0 to update panel when train OpTimeToAct updated (updated earlier)
8273  }
8274  TrainController->SignallerTrainRemovedOnAutoSigsRoute = false; // added at v1.3.0 to ensure doesn't persist beyond one call
8275  }
8276 
8277  else if(Level2OperMode == Paused) //added after v2.4.3 to show actions due after a session file reloaded
8278  {
8280  {
8281  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
8282  {
8284  }
8287  }
8288  }
8289 
8290 // plot trains in ZoomOut mode & flash trains where attention needed alternately on & off at each call
8291 // by examining Flash
8292  if((Level1Mode == OperMode) && (Display->ZoomOutFlag))
8293  {
8295  }
8296 
8297 // Deal with any flashing graphics
8299  {
8300  FlashingGraphics(0, Now); // only call when WarningFlash changes
8301  if(Level1Mode == OperMode)
8302  {
8303  if(WarningFlash)
8304  {
8306  {
8307  CrashImage->Visible = true;
8308  }
8310  {
8311  DerailImage->Visible = true;
8312  }
8314  {
8315  SPADImage->Visible = true;
8316  }
8318  {
8319  TrainFailedImage->Visible = true;
8320  }
8322  {
8323  CallOnImage->Visible = true;
8324  }
8326  {
8327  SignalStopImage->Visible = true;
8328  }
8330  {
8331  BufferAttentionImage->Visible = true;
8332  }
8333  }
8334  else
8335  {
8336  CrashImage->Visible = false;
8337  DerailImage->Visible = false;
8338  SPADImage->Visible = false;
8339  TrainFailedImage->Visible = false;
8340  CallOnImage->Visible = false;
8341  SignalStopImage->Visible = false;
8342  BufferAttentionImage->Visible = false;
8343  }
8344  }
8345  else
8346  {
8347  CrashImage->Visible = false;
8348  DerailImage->Visible = false;
8349  SPADImage->Visible = false;
8350  TrainFailedImage->Visible = false;
8351  CallOnImage->Visible = false;
8352  SignalStopImage->Visible = false;
8353  BufferAttentionImage->Visible = false;
8354  }
8355  } // if(WarningFlashCount == 0)
8356  // set buttons etc as appropriate
8358  // if forced route cancellation flag set redisplay to clear the cancelled route
8360  {
8362  AllRoutes->RebuildRailwayFlag = false;
8363  }
8364  // deal with approach locking
8366  // deal with ContinuationAutoSigList
8368  // FloatingLabel function
8369  if((TrackInfoOnOffMenuItem->Caption == "Hide") || (TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") ||
8370  (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable"))
8371  {
8372  TrackTrainFloat(0);
8373  }
8374  else
8375  {
8376  FloatingPanel->Visible = false;
8377  }
8378  // PerformanceLog check function
8379 /*
8380  if(IsPerformancePanelObscuringFloatingLabel(0) && (ShowPerformancePanel))
8381  {
8382  PerformancePanel->Visible = false;
8383  }
8384  else
8385  {
8386 */
8388  {
8389  PerformancePanel->Visible = true;
8390  }
8391  else
8392  {
8393  PerformancePanel->Visible = false;
8394  }
8395 
8397  {
8398  OperatorActionPanel->Visible = true;
8399  }
8400  else
8401  {
8402  OperatorActionPanel->Visible = false;
8403  }
8404 
8405 // }
8406 
8407  // check if a moving train is present on a route-under-construction start element & cancel it if so
8408  if(RouteMode == RouteContinuing)
8409  {
8410  bool FoundFlag;
8411  int RouteStartVecPos;
8412  if(AutoSigsFlag)
8414  FoundFlag);
8415  else if(PreferredRoute) //added at v2.7.0, was ConsecSignalsRoute
8416  RouteStartVecPos = Track->GetVectorPositionFromTrackMap(8, (SigRouteStartMarker->GetHPos()) / 16, (SigRouteStartMarker->GetVPos()) / 16,
8417  FoundFlag);
8418  else
8420  FoundFlag);
8421  if(FoundFlag && (RouteStartVecPos > -1))
8422  {
8423  TTrackElement TrackElement = Track->TrackElementAt(485, RouteStartVecPos);
8424  if(TrackElement.TrainIDOnElement > -1)
8425  {
8426  if(!(TrainController->TrainVectorAtIdent(2, TrackElement.TrainIDOnElement).Stopped()))
8427  {
8429  // replot train as above erases the front element of the train
8431  }
8432  }
8433  }
8434  }
8435  Utilities->CallLogPop(81);
8436  }
8437  catch(const Exception &e)
8438  {
8439  ErrorLog(25, e.Message);
8440  }
8441 }
8442 
8443 // ---------------------------------------------------------------------------
8444 
8445 void __fastcall TInterface::CallingOnButtonClick(TObject *Sender)
8446 {
8447  try
8448  {
8449  TrainController->LogEvent("CallingOnButtonClick");
8450  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CallingOnButtonClick");
8451  if(CallingOnButton->Down)
8452  {
8453  // CallingOnButton->Down = true;
8454  InfoPanel->Visible = true;
8455  InfoPanel->Caption = "CALLING ON: Select signal for call on";
8456  }
8457  else
8458  {
8459  // CallingOnButton->Down = false;
8461  }
8462  AutoRouteStartMarker->PlotOriginal(29, Display); // if overlay not plotted will ignore
8463  SigRouteStartMarker->PlotOriginal(30, Display); // if overlay not plotted will ignore
8464  NonSigRouteStartMarker->PlotOriginal(31, Display); // if overlay not plotted will ignore
8465  CallingOnButton->Enabled = false;
8466 // added at v1.3.0 to ensure doesn't retain focus - will be re-enabled during ClockTimer2 (in SetSaveMenuAndButtons) if required
8467  Utilities->CallLogPop(82);
8468  }
8469  catch(const Exception &e)
8470  {
8471  ErrorLog(26, e.Message);
8472  }
8473 }
8474 
8475 // ---------------------------------------------------------------------------
8476 void __fastcall TInterface::ScreenLeftButtonClick(TObject *Sender)
8477 {
8478  try
8479  {
8480  // have to allow in zoomout mode
8481  TrainController->LogEvent("ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8482  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8483  Screen->Cursor = TCursor(-11); // Hourglass;
8484  ScreenLeftButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8485  if(!Display->ZoomOutFlag)
8486  {
8487  if(CtrlKey)
8488  {
8489  Display->DisplayOffsetH -= 2;
8490  }
8491  else if(ShiftKey)
8492  {
8494  }
8495  else
8496  {
8498  }
8501  {
8503  }
8504  }
8505  else
8506  {
8507  if(CtrlKey)
8508  {
8510  }
8511  else if(ShiftKey)
8512  {
8514  }
8515  else
8516  {
8518  }
8519  Display->ClearDisplay(0);
8522  Track->PlotSmallRedGap(0);
8523  }
8524  ScreenLeftButton->Enabled = true;
8525  Screen->Cursor = TCursor(-2); // Arrow
8526  Utilities->CallLogPop(83);
8527  }
8528  catch(const Exception &e)
8529  {
8530  ErrorLog(27, e.Message);
8531  }
8532 }
8533 // ---------------------------------------------------------------------------
8534 
8535 void __fastcall TInterface::ScreenRightButtonClick(TObject *Sender)
8536 {
8537  try
8538  {
8539  // have to allow in zoomout mode
8540  TrainController->LogEvent("ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8541  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8542  Screen->Cursor = TCursor(-11); // Hourglass;
8543  ScreenRightButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8544  if(!Display->ZoomOutFlag)
8545  {
8546  if(CtrlKey)
8547  {
8548  Display->DisplayOffsetH += 2;
8549  }
8550  else if(ShiftKey)
8551  {
8553  }
8554  else
8555  {
8557  }
8560  {
8562  }
8563  }
8564  else
8565  {
8566  if(CtrlKey)
8567  {
8569  }
8570  else if(ShiftKey)
8571  {
8573  }
8574  else
8575  {
8577  }
8578  Display->ClearDisplay(1);
8581  Track->PlotSmallRedGap(1);
8582  }
8583  ScreenRightButton->Enabled = true;
8584  Screen->Cursor = TCursor(-2); // Arrow
8585  Utilities->CallLogPop(84);
8586  }
8587  catch(const Exception &e)
8588  {
8589  ErrorLog(28, e.Message);
8590  }
8591 }
8592 // ---------------------------------------------------------------------------
8593 
8594 void __fastcall TInterface::ScreenDownButtonClick(TObject *Sender)
8595 {
8596  try
8597  {
8598  // have to allow in zoomout mode
8599  TrainController->LogEvent("ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8600  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8601  Screen->Cursor = TCursor(-11); // Hourglass;
8602  ScreenDownButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8603  // BUT - it does prevent it from retaining focus - so can use the cursor keys to scroll the display without being captured by the buttons
8604  if(!Display->ZoomOutFlag)
8605  {
8606  if(CtrlKey)
8607  {
8608  Display->DisplayOffsetV += 2;
8609  }
8610  else if(ShiftKey)
8611  {
8613  }
8614  else
8615  {
8617  }
8620  {
8622  }
8623  }
8624  else
8625  {
8626  if(CtrlKey)
8627  {
8629  }
8630  else if(ShiftKey)
8631  {
8633  }
8634  else
8635  {
8637  }
8638  Display->ClearDisplay(2);
8641  Track->PlotSmallRedGap(2);
8642  }
8643  ScreenDownButton->Enabled = true;
8644  Screen->Cursor = TCursor(-2); // Arrow
8645  Utilities->CallLogPop(85);
8646  }
8647  catch(const Exception &e)
8648  {
8649  ErrorLog(29, e.Message);
8650  }
8651 }
8652 // ---------------------------------------------------------------------------
8653 
8654 void __fastcall TInterface::ScreenUpButtonClick(TObject *Sender)
8655 {
8656  try
8657  {
8658  // have to allow in zoomout mode
8659  TrainController->LogEvent("ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8660  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8661  Screen->Cursor = TCursor(-11); // Hourglass;
8662  ScreenUpButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8663  if(!Display->ZoomOutFlag)
8664  {
8665  if(CtrlKey)
8666  {
8667  Display->DisplayOffsetV -= 2;
8668  }
8669  else if(ShiftKey)
8670  {
8672  }
8673  else
8674  {
8676  }
8679  {
8681  }
8682  }
8683  else
8684  {
8685  if(CtrlKey)
8686  {
8688  }
8689  else if(ShiftKey)
8690  {
8692  }
8693  else
8694  {
8696  }
8697  Display->ClearDisplay(3);
8700  Track->PlotSmallRedGap(3);
8701  }
8702  ScreenUpButton->Enabled = true;
8703  Screen->Cursor = TCursor(-2); // Arrow
8704  Utilities->CallLogPop(86);
8705  }
8706  catch(const Exception &e)
8707  {
8708  ErrorLog(30, e.Message);
8709  }
8710 }
8711 // ---------------------------------------------------------------------------
8712 
8713 void __fastcall TInterface::ZoomButtonClick(TObject *Sender)
8714 {
8715  try
8716  {
8717  // have to allow in zoomout mode
8718  TrainController->LogEvent("ZoomButtonClick");
8719  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ZoomButtonClick");
8720  Screen->Cursor = TCursor(-11); // Hourglass;
8721  ZoomButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
8722  if(Display->ZoomOutFlag) // i.e resume zoomed in view
8723  {
8724  TrainController->LogEvent("ZoomButtonClick + ZoomOutFlag");
8725 // TLevel2OperMode TempLevel2OperMode = Level2OperMode;
8726  if(Level1Mode == BaseMode)
8727  {
8728  InfoPanel->Visible = false; // reset infopanel in case not set later
8729  InfoPanel->Caption = "";
8730  SetLevel1Mode(18);
8731  }
8732  else if(Level1Mode == TrackMode)
8733  {
8734  InfoPanel->Visible = false; // reset infopanel in case not set later
8735  InfoPanel->Caption = "";
8736  // set edit menu items
8738  SetLevel2TrackMode(33); // revert to earlier track mode from zoom
8739  }
8740  else if(Level1Mode == PrefDirMode)
8741  {
8743  SetLevel1Mode(19); // to redisplay infopanel caption "...select start..."
8744  else
8745  SetLevel2PrefDirMode(4); // revert to PrefDirContinuing PrefDir mode
8746  }
8747 // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
8748 // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
8749  else if(Level1Mode == TimetableMode)
8750  {
8751  InfoPanel->Visible = false;
8752  }
8753  // Don't include OperMode or RestartSessionOperMode as they reset the performance file
8754  else if(Level2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
8755  {
8756  OperateButton->Enabled = true;
8757  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
8758  ExitOperationButton->Enabled = true;
8760  }
8761  else if(Level2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
8762  {
8763  OperateButton->Enabled = true;
8764  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
8765  ExitOperationButton->Enabled = true;
8766  TTClockAdjButton->Enabled = true;
8769  }
8770  else if(Level2OperMode == PreStart)
8771  {
8772  OperateButton->Enabled = true;
8773  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
8774  ExitOperationButton->Enabled = true;
8775  TTClockAdjButton->Enabled = true;
8777  }
8778  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
8780  ClearandRebuildRailway(43); // need to call this after ZoomOutFlag reset to display track, even if Clearand... already called
8781  // earlier during level mode setting - because until ZoomOutFlag reset PlotOutput plots nothing
8782  }
8783  else // set zoomed out view
8784  {
8785  TrainController->LogEvent("ZoomButtonClick + != ZoomOutFlag");
8786  Display->ZoomOutFlag = true;
8788  FileMenu->Enabled = false;
8789  ModeMenu->Enabled = false;
8790  EditMenu->Enabled = false;
8791  TextBox->Visible = false;
8792  LocationNameTextBox->Visible = false;
8793  TTClockAdjButton->Enabled = false;
8794 // DisablePanelsStoreMainMenuStates();//ensure Display->ZoomOutFlag set true before calling
8795  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
8796  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
8797 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
8798  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
8799  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
8800  if((LeftExcess > 0) && (RightExcess > 0))
8801  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
8802  else if((LeftExcess > 0) && (RightExcess <= 0))
8803  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
8804  (Utilities->ScreenElementWidth / 2); // normalise to nearest screen
8805  else if((LeftExcess <= 0) && (RightExcess > 0))
8806  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
8807  else
8808  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
8809 
8810  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
8811  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
8812  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
8813  if((TopExcess > 0) && (BotExcess > 0))
8814  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
8815  else if((TopExcess > 0) && (BotExcess <= 0))
8816  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
8817  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
8818  else if((TopExcess <= 0) && (BotExcess > 0))
8819  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
8820  else
8821  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
8822 
8823  Display->ClearDisplay(4);
8827  Track->PlotSmallRedGap(4);
8828  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomIn");
8829  }
8830  Screen->Cursor = TCursor(-2); // Arrow
8831  ZoomButton->Enabled = true; // restore, see above
8832  Utilities->CallLogPop(87);
8833  }
8834  catch(const Exception &e)
8835  {
8836  ErrorLog(31, e.Message);
8837  }
8838 }
8839 // ---------------------------------------------------------------------------
8840 
8841 void __fastcall TInterface::HomeButtonClick(TObject *Sender)
8842 {
8843  try
8844  {
8845  // have to allow in zoomout mode
8846  TrainController->LogEvent("HomeButtonClick");
8847  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",HomeButtonClick");
8848  Screen->Cursor = TCursor(-11); // Hourglass;
8849  HomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
8850  if(!Display->ZoomOutFlag) // zoomed in mode
8851  {
8852  TrainController->LogEvent("HomeButtonClick + zoomed in mode");
8856  {
8858  }
8859  }
8860  else
8861  {
8862  // zoomed out mode
8863  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
8864  TrainController->LogEvent("HomeButtonClick + zoomed out mode");
8866  Display->ClearDisplay(9);
8869  Track->PlotSmallRedGap(5);
8870  }
8871  Screen->Cursor = TCursor(-2); // Arrow
8872  HomeButton->Enabled = true; // restore, see above
8873  Utilities->CallLogPop(88);
8874  }
8875  catch(const Exception &e)
8876  {
8877  ErrorLog(32, e.Message);
8878  }
8879 }
8880 
8881 // ---------------------------------------------------------------------------
8882 void __fastcall TInterface::NewHomeButtonClick(TObject *Sender)
8883 {
8884  try
8885  {
8886  TrainController->LogEvent("NewHomeButtonClick");
8887  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewHomeButtonClick");
8888  NewHomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
8889  if(!Display->ZoomOutFlag) // zoomed in mode
8890  {
8893  ResetChangedFileDataAndCaption(23, false); // false because no major changes made
8894  }
8895  else
8896  {
8899  }
8900  Utilities->CallLogPop(1188);
8901  NewHomeButton->Enabled = true; // restore, see above
8902  }
8903  catch(const Exception &e)
8904  {
8905  ErrorLog(174, e.Message);
8906  }
8907 }
8908 
8909 // ---------------------------------------------------------------------------
8910 void __fastcall TInterface::EditMenuClick(TObject *Sender)
8911  // added at v2.1.0 to allow CTRL+X, CTRL+C & CTRL+V in edit menu (see case BaseMode for more information)
8912 {
8913  try
8914  {
8915  CopyMenuItem->ShortCut = TextToShortCut("Ctrl+C");
8916  CutMenuItem->ShortCut = TextToShortCut("Ctrl+X");
8917  PasteMenuItem->ShortCut = TextToShortCut("Ctrl+V");
8918  }
8919  catch(const Exception &e)
8920  {
8921  ErrorLog(196, e.Message);
8922  }
8923 }
8924 
8925 // ---------------------------------------------------------------------------
8926 void __fastcall TInterface::SelectMenuItemClick(TObject *Sender)
8927 {
8928 // draw a rectangle with the left mouse button, enclosing whole 16 x 16 squares
8929  try
8930  {
8931  TrainController->LogEvent("SelectMenuItemClick");
8932  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectMenuItemClick");
8933  if(Level1Mode == TrackMode)
8934  {
8935  SelectionValid = false;
8937  SetLevel2TrackMode(34);
8939  {
8940  ShowMessage("Please be aware when pasting that anything inside the pasted area will be overwritten.\n\nThis warning will not be shown again.");
8941  PasteWarningSentFlag = true;
8942  }
8943  }
8944  else if(Level1Mode == PrefDirMode)
8945  {
8948  }
8949  Utilities->CallLogPop(1189);
8950  }
8951  catch(const Exception &e)
8952  {
8953  ErrorLog(145, e.Message);
8954  }
8955 }
8956 
8957 // ---------------------------------------------------------------------------
8958 void __fastcall TInterface::ReselectMenuItemClick(TObject *Sender)
8959 {
8960  try
8961  {
8962  TrainController->LogEvent("ReselectMenuItemClick");
8963  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectMenuItemClick");
8964  if((SelectBitmap->Height == 0) || (SelectBitmap->Width == 0))
8965  {
8966  Utilities->CallLogPop(1424);
8967  return;
8968  }
8969 
8970  int TLHCH = SelectBitmapHLoc;
8971  int TLHCV = SelectBitmapVLoc;
8972  int BRHCH = TLHCH + (SelectBitmap->Width / 16);
8973  int BRHCV = TLHCV + (SelectBitmap->Height / 16);
8974  TRect NewSelectRect(TLHCH, TLHCV, BRHCH, BRHCV);
8975  SelectRect = NewSelectRect;
8977  // set bitmap to reselected area (may be different if flip or mirror had been selected earlier)
8978  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
8979  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
8980  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
8981  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
8982 
8983  SelectionValid = true;
8984  ReselectMenuItem->Enabled = false;
8985  CutMenuItem->Enabled = true;
8986  CopyMenuItem->Enabled = true;
8987  FlipMenuItem->Enabled = true;
8988  MirrorMenuItem->Enabled = true;
8989  RotRightMenuItem->Enabled = true;
8990  RotLeftMenuItem->Enabled = true;
8991  RotateMenuItem->Enabled = true;
8992  PasteMenuItem->Enabled = false;
8993  DeleteMenuItem->Enabled = true;
8994  if(Track->IsTrackFinished())
8995  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
8996  else
8997  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
8998  SelectBiDirPrefDirsMenuItem->Visible = false;
8999  CancelSelectionMenuItem->Enabled = true;
9000  mbLeftDown = false;
9001  // Level1Mode = TrackMode;
9002  // SetLevel1Mode(68);
9004  SetLevel2TrackMode(47);
9005  Utilities->CallLogPop(1425);
9006  }
9007  catch(const Exception &e)
9008  {
9009  ErrorLog(146, e.Message);
9010  }
9011 }
9012 
9013 // ---------------------------------------------------------------------------
9014 void __fastcall TInterface::CutMenuItemClick(TObject *Sender)
9015 {
9016  try
9017  {
9018  TrainController->LogEvent("CutMenuItemClick");
9019  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutMenuItemClick");
9020  // Level1Mode = TrackMode;
9021  // SetLevel1Mode(69);
9023  SetLevel2TrackMode(35);
9024  Utilities->CallLogPop(1190);
9025  }
9026  catch(const Exception &e)
9027  {
9028  ErrorLog(147, e.Message);
9029  }
9030 }
9031 // ---------------------------------------------------------------------------
9032 
9033 void __fastcall TInterface::CopyMenuItemClick(TObject *Sender)
9034 {
9035  try
9036  {
9037  TrainController->LogEvent("CopyMenuItemClick");
9038  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyMenuItemClick");
9039  // Level1Mode = TrackMode;
9040  // SetLevel1Mode(70);
9042  SetLevel2TrackMode(36);
9043  Utilities->CallLogPop(1191);
9044  }
9045  catch(const Exception &e)
9046  {
9047  ErrorLog(148, e.Message);
9048  }
9049 }
9050 
9051 // ---------------------------------------------------------------------------
9052 void __fastcall TInterface::FlipMenuItemClick(TObject *Sender)
9053 {
9054  try
9055  {
9056  TrainController->LogEvent("FlipMenuItemClick");
9057  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FlipMenuItemClick");
9058  // reset values in SelectVector
9059  int VerSum = SelectRect.top + SelectRect.bottom - 1;
9060  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9061  {
9062  // Note: (changed again in v2.4.0 to keep attributes) need to change flip, mirror & 180deg functions as only change speedtag without changing anything else.
9063  // This didn't matter before new paste with attributes added at v2.2.0 as a new element was built from the speedtag,
9064  // but now if do a reselect then cut and paste with attributes the wrong graphic is pasted and all other attributes
9065  // are wrong. Need to rebuild a new TrackElement from the new speedtag and use that in the select vector.
9066  // Note that if use Flip, mirror etc then all attributes lost anyway so ok to build a basic element.
9067  int VLoc = VerSum - Track->SelectVectorAt(8, x).VLoc;
9068  int HLoc = Track->SelectVectorAt(7, x).HLoc;
9070  TE.VLoc = VLoc;
9071  TE.HLoc = HLoc;
9072 
9073  TE.ActiveTrackElementName = Track->SelectVectorAt(37, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9075  TE.Length01 = Track->SelectVectorAt(39, x).Length01;
9076  TE.Length23 = Track->SelectVectorAt(40, x).Length23;
9079  TE.SigAspect = Track->SelectVectorAt(43, x).SigAspect;
9080  Track->SelectVectorAt(26, x) = TE;
9081  }
9082  // reset values in SelectTextVector
9083  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(0); x++)
9084  {
9086  // also subtract font height, brings position approximately right
9087  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
9088  }
9089  // reset values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
9090  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9091  {
9092  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
9093  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
9094  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
9095  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
9096  }
9098  SetLevel2TrackMode(48);
9099  Utilities->CallLogPop(1426);
9100  }
9101  catch(const Exception &e)
9102  {
9103  ErrorLog(149, e.Message);
9104  }
9105 }
9106 
9107 // ---------------------------------------------------------------------------
9108 void __fastcall TInterface::MirrorMenuItemClick(TObject *Sender)
9109 {
9110  try
9111  {
9112  TrainController->LogEvent("MirrorMenuItemClick");
9113  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MirrorMenuItemClick");
9114  // reset values in SelectVector
9115  int HorSum = SelectRect.left + SelectRect.right - 1;
9116  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9117  {
9118  // See note above for FlipMenuItem relating to mods for v2.2.0
9119  int VLoc = Track->SelectVectorAt(22, x).VLoc;
9120  int HLoc = HorSum - Track->SelectVectorAt(6, x).HLoc;
9122  TE.VLoc = VLoc;
9123  TE.HLoc = HLoc;
9124 
9125  TE.ActiveTrackElementName = Track->SelectVectorAt(44, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9127  TE.Length01 = Track->SelectVectorAt(46, x).Length01;
9128  TE.Length23 = Track->SelectVectorAt(47, x).Length23;
9131  TE.SigAspect = Track->SelectVectorAt(50, x).SigAspect;
9132 
9133 // if(Track->SelectVectorAt(28, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(29, x).SigAspect;//TrackType will be the same
9134  Track->SelectVectorAt(30, x) = TE;
9135 // Track->SelectVectorAt(, x).HLoc = HorSum - Track->SelectVectorAt(, x).HLoc;
9136 // Track->SelectVectorAt(, x).SpeedTag = Track->MirrorArray[Track->SelectVectorAt(, x).SpeedTag];
9137  }
9138  // reset values in SelectTextVector
9139  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(1); x++)
9140  {
9142  // also subtract half font height for each letter of text, brings position approximately right
9143  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
9144  }
9145  // reset values in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
9146  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9147  {
9148  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
9149  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
9150  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
9151  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
9152  {
9153  LeftPosAfterMirror = SelectRect.left * 16;
9154  }
9155  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
9156  }
9158  SetLevel2TrackMode(49);
9159  Utilities->CallLogPop(1427);
9160  }
9161  catch(const Exception &e)
9162  {
9163  ErrorLog(150, e.Message);
9164  }
9165 }
9166 
9167 // ---------------------------------------------------------------------------
9168 void __fastcall TInterface::RotateMenuItemClick(TObject *Sender)
9169 {
9170  try
9171  {
9172  TrainController->LogEvent("Rotate180MenuItemClick");
9173  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",Rotate180MenuItemClick");
9174  // reset values in SelectVector
9175  int HorSum = SelectRect.left + SelectRect.right - 1;
9176  int VerSum = SelectRect.top + SelectRect.bottom - 1;
9177  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9178  {
9179  // See note above for FlipMenuItem relating to mods for v2.2.0
9180  int VLoc = VerSum - Track->SelectVectorAt(23, x).VLoc;
9181  int HLoc = HorSum - Track->SelectVectorAt(36, x).HLoc;
9183  TE.VLoc = VLoc;
9184  TE.HLoc = HLoc;
9185 
9186  TE.ActiveTrackElementName = Track->SelectVectorAt(51, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9188  TE.Length01 = Track->SelectVectorAt(53, x).Length01;
9189  TE.Length23 = Track->SelectVectorAt(54, x).Length23;
9192  TE.SigAspect = Track->SelectVectorAt(57, x).SigAspect;
9193 
9194 // if(Track->SelectVectorAt(32, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(33, x).SigAspect; dropped in v2.4.0 for above
9195  Track->SelectVectorAt(34, x) = TE;
9196 // TTrackElement &TempEl = Track->SelectVectorAt(13, x);
9197 // TempEl.HLoc = HorSum - TempEl.HLoc;
9198 // TempEl.VLoc = VerSum - TempEl.VLoc;
9199 // TempEl.SpeedTag = Track->MirrorArray[Track->FlipArray[TempEl.SpeedTag]];
9200  }
9201  // reset values in SelectTextVector
9202  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(2); x++)
9203  {
9205  // also subtract half font height for each letter of text, brings position approximately right horizontally
9206  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
9207  // also subtract font height, brings position approximately right vertically
9208  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
9209  }
9210  // reset flip values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
9211  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9212  {
9213  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
9214  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
9215  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
9216  if(TopPosAfterFlip < (SelectRect.top * 16)) // shouldn't go above top but check
9217  {
9218  TopPosAfterFlip = SelectRect.top * 16;
9219  }
9220  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
9221  }
9222  // reset mirror in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
9223  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9224  {
9225  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
9226  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
9227  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
9228  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
9229  {
9230  LeftPosAfterMirror = SelectRect.left * 16;
9231  }
9232  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
9233  }
9234  // Level1Mode = TrackMode;
9235  // SetLevel1Mode(73);
9237  SetLevel2TrackMode(50);
9238  Utilities->CallLogPop(1435);
9239  }
9240  catch(const Exception &e)
9241  {
9242  ErrorLog(151, e.Message);
9243  }
9244 }
9245 // ---------------------------------------------------------------------------
9246 
9247 void __fastcall TInterface::RotRightMenuItemClick(TObject *Sender)
9248 {
9249  try
9250  {
9251  TrainController->LogEvent("RotateRight90MenuItemClick");
9252  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateRight90MenuItemClick");
9253  Screen->Cursor = TCursor(-11); // Hourglass
9254  // check first if a square and if not give message & quit
9255  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
9256  {
9257  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
9258  int VertSize = SelectRect.bottom - SelectRect.top;
9259  if((SelectRect.Left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
9260  {
9261  // use right hand vertical & make square to left of that
9262  SelectRect.left = SelectRect.right - VertSize;
9263  }
9264  else
9265  {
9266  SelectRect.right = SelectRect.left + VertSize;
9267  }
9270  int button = Application->MessageBox
9271  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
9272  L"Left click and hold here to move this message box", MB_OKCANCEL);
9273  if(button == IDCANCEL)
9274  {
9275  ResetSelectRect();
9276  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
9277  SetLevel1Mode(133);
9279  SetLevel2TrackMode(59);
9281  Screen->Cursor = TCursor(-2); // Arrow
9282  Utilities->CallLogPop(2121);
9283  return;
9284  }
9285  }
9286  // set SelectBitmap (only need the dimensions here as not moving the selection)
9289  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
9290  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
9291  // store track elements and text in select vectors
9293  TTrackElement TempElement; // default element
9294  bool FoundFlag;
9295  for(int x = SelectRect.left; x < SelectRect.right; x++)
9296  {
9297  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9298  {
9299  int ATVecPos = Track->GetVectorPositionFromTrackMap(57, x, y, FoundFlag);
9300  if(FoundFlag)
9301  {
9302  TempElement = Track->TrackElementAt(959, ATVecPos);
9303  if(TempElement.SpeedTag > 0)
9304  Track->SelectPush(TempElement);
9305  }
9306  }
9307  }
9308  // now store inactive elements
9309  for(int x = SelectRect.left; x < SelectRect.right; x++)
9310  {
9311  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9312  {
9313  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(28, x, y, FoundFlag);
9314  if(FoundFlag)
9315  {
9316  TempElement = Track->InactiveTrackElementAt(126, IATVecPair.first);
9317  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
9318  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
9319  {
9320  TempElement = Track->InactiveTrackElementAt(127, IATVecPair.second);
9321  Track->SelectPush(TempElement);
9322  }
9323  }
9324  }
9325  }
9326  // store text items
9327  int LowSelectHPos = SelectRect.left * 16;
9328  int HighSelectHPos = SelectRect.right * 16;
9329  int LowSelectVPos = SelectRect.top * 16;
9330  int HighSelectVPos = SelectRect.bottom * 16;
9331  TextHandler->SelectTextVector.clear();
9332  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
9333  {
9334  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
9335  {
9336  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
9337  {
9338  // have to create a new TextItem in order to create a new Font object
9339  // BUT: only create new items where they don't appear as named location names
9340  // in SelectVector, since those names shouldn't be copied or pasted.
9341  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
9342  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
9343  bool SelectVectorNamedElement = false;
9344  AnsiString SelectTextString; // new at v2.2.0
9345  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
9346  {
9347  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
9348  {
9349  SelectVectorNamedElement = true;
9350  break;
9351  }
9352  }
9353  if(SelectVectorNamedElement) // changed at v2.2.0
9354  {
9355  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
9356  }
9357  else // new at v2.2.0
9358  {
9359  SelectTextString = TextPtr->TextString;
9360  }
9361  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
9362  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
9363  }
9364  }
9365  }
9366  // store graphic items, but first clear SelectGraphicVector
9367  Track->SelectGraphicVector.clear();
9368  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
9369  {
9370  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
9371  UserGraphicPtr++)
9372  {
9373  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
9374  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
9375  {
9376  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
9377  }
9378  }
9379  }
9380  // now transform the H & V for rh rotate
9381  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9382  {
9383  int HLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(74, x).VLoc;
9384  int VLoc = SelectRect.top - SelectRect.left + Track->SelectVectorAt(75, x).HLoc;
9386  TE.VLoc = VLoc;
9387  TE.HLoc = HLoc;
9388 
9389  TE.ActiveTrackElementName = Track->SelectVectorAt(58, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9391  TE.Length01 = Track->SelectVectorAt(60, x).Length01;
9392  TE.Length23 = Track->SelectVectorAt(61, x).Length23;
9395  TE.SigAspect = Track->SelectVectorAt(64, x).SigAspect;
9396  Track->SelectVectorAt(65, x) = TE;
9397  }
9398  // reset values in SelectTextVector
9399  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(3); x++)
9400  {
9401 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
9402 // & if a lot then some will extend beyond the selection
9404  // also subtract half font height for each letter of text, brings position approximately right horizontally
9405  TextItem->HPos = (SelectRect.left) * 16;
9406  TextItem->VPos = (SelectRect.top + x) * 16;
9407  }
9408  // reset values in SelectGraphicVector
9409  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9410  {
9411  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
9412  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
9413  int MidHPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidVPosBeforeRotate;
9414  int MidVPosAfterRotate = ((SelectRect.top - SelectRect.left) * 16) + MidHPosBeforeRotate;
9415  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
9416  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
9417  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
9418  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
9419  }
9420  Screen->Cursor = TCursor(-2); // Arrow
9422  SetLevel2TrackMode(60);
9423  Utilities->CallLogPop(2122);
9424  }
9425  catch(const Exception &e)
9426  {
9427  ErrorLog(205, e.Message);
9428  }
9429 }
9430 
9431 // ---------------------------------------------------------------------------
9432 
9433 void __fastcall TInterface::RotLeftMenuItemClick(TObject *Sender)
9434 {
9435  try
9436  {
9437  TrainController->LogEvent("RotateLeft90MenuItemClick");
9438  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateLeft90MenuItemClick");
9439  Screen->Cursor = TCursor(-11); // Hourglass;
9440  // check first if a square and if not give message & quit
9441  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
9442  {
9443  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
9444  int VertSize = SelectRect.bottom - SelectRect.top;
9445  if((SelectRect.Left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
9446  {
9447  // use right hand vertical & make square to left of that
9448  SelectRect.left = SelectRect.right - VertSize;
9449  }
9450  else
9451  {
9452  SelectRect.right = SelectRect.left + VertSize;
9453  }
9456  int button = Application->MessageBox
9457  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
9458  L"Left click and hold here to move this message box", MB_OKCANCEL);
9459  if(button == IDCANCEL)
9460  {
9461  ResetSelectRect();
9462  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
9463  SetLevel1Mode(134);
9465  SetLevel2TrackMode(61);
9467  Screen->Cursor = TCursor(-2); // Arrow
9468  Utilities->CallLogPop(2123);
9469  return;
9470  }
9471  }
9472  // set SelectBitmap (only need the dimensions here as not moving the selection)
9475  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
9476  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
9477  // store track elements and text in select vectors
9479  TTrackElement TempElement; // default element
9480  bool FoundFlag;
9481  for(int x = SelectRect.left; x < SelectRect.right; x++)
9482  {
9483  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9484  {
9485  int ATVecPos = Track->GetVectorPositionFromTrackMap(58, x, y, FoundFlag);
9486  if(FoundFlag)
9487  {
9488  TempElement = Track->TrackElementAt(960, ATVecPos);
9489  if(TempElement.SpeedTag > 0)
9490  Track->SelectPush(TempElement);
9491  }
9492  }
9493  }
9494  // now store inactive elements
9495  for(int x = SelectRect.left; x < SelectRect.right; x++)
9496  {
9497  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9498  {
9499  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(29, x, y, FoundFlag);
9500  if(FoundFlag)
9501  {
9502  TempElement = Track->InactiveTrackElementAt(128, IATVecPair.first);
9503  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
9504  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
9505  {
9506  TempElement = Track->InactiveTrackElementAt(129, IATVecPair.second);
9507  Track->SelectPush(TempElement);
9508  }
9509  }
9510  }
9511  }
9512  // store text items
9513  int LowSelectHPos = SelectRect.left * 16;
9514  int HighSelectHPos = SelectRect.right * 16;
9515  int LowSelectVPos = SelectRect.top * 16;
9516  int HighSelectVPos = SelectRect.bottom * 16;
9517  TextHandler->SelectTextVector.clear();
9518  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
9519  {
9520  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
9521  {
9522  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
9523  {
9524  // have to create a new TextItem in order to create a new Font object
9525  // BUT: only create new items where they don't appear as named location names
9526  // in SelectVector, since those names shouldn't be copied or pasted.
9527  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
9528  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
9529  bool SelectVectorNamedElement = false;
9530  AnsiString SelectTextString; // new at v2.2.0
9531  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
9532  {
9533  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
9534  {
9535  SelectVectorNamedElement = true;
9536  break;
9537  }
9538  }
9539  if(SelectVectorNamedElement) // changed at v2.2.0
9540  {
9541  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
9542  }
9543  else // new at v2.2.0
9544  {
9545  SelectTextString = TextPtr->TextString;
9546  }
9547  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
9548  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
9549  }
9550  }
9551  }
9552  // store graphic items, but first clear SelectGraphicVector
9553  Track->SelectGraphicVector.clear();
9554  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
9555  {
9556  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
9557  UserGraphicPtr++)
9558  {
9559  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
9560  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
9561  {
9562  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
9563  }
9564  }
9565  }
9566  // now transform the H & V for lh rotate
9567  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9568  {
9569  int HLoc = SelectRect.left - SelectRect.top + Track->SelectVectorAt(76, x).VLoc;
9570  int VLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(77, x).HLoc;
9572  TE.VLoc = VLoc;
9573  TE.HLoc = HLoc;
9574 
9575  TE.ActiveTrackElementName = Track->SelectVectorAt(66, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9577  TE.Length01 = Track->SelectVectorAt(68, x).Length01;
9578  TE.Length23 = Track->SelectVectorAt(69, x).Length23;
9581  TE.SigAspect = Track->SelectVectorAt(72, x).SigAspect;
9582  Track->SelectVectorAt(73, x) = TE;
9583  }
9584  // reset values in SelectTextVector
9585  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(4); x++)
9586  {
9587 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
9588 // & if a lot then some will extend beyond the selection
9590  // also subtract half font height for each letter of text, brings position approximately right horizontally
9591  TextItem->HPos = (SelectRect.left) * 16;
9592  TextItem->VPos = (SelectRect.top + x) * 16;
9593  }
9594  // reset values in SelectGraphicVector
9595  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9596  {
9597  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
9598  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
9599  int MidHPosAfterRotate = ((SelectRect.left - SelectRect.top) * 16) + MidVPosBeforeRotate;
9600  int MidVPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidHPosBeforeRotate;
9601  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
9602  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
9603  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
9604  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
9605  }
9606  Screen->Cursor = TCursor(-2); // Arrow
9608  SetLevel2TrackMode(62);
9609  Utilities->CallLogPop(2124);
9610  }
9611  catch(const Exception &e)
9612  {
9613  ErrorLog(206, e.Message);
9614  }
9615 }
9616 
9617 // ---------------------------------------------------------------------------
9618 
9619 void __fastcall TInterface::PasteMenuItemClick(TObject *Sender)
9620 {
9621  try
9622  {
9623  TrainController->LogEvent("PasteMenuItemClick");
9624  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteMenuItemClick");
9625  // Level1Mode = TrackMode;
9626  // SetLevel1Mode(74);
9628  SetLevel2TrackMode(58);
9629  Utilities->CallLogPop(2060);
9630  }
9631  catch(const Exception &e)
9632  {
9633  ErrorLog(198, e.Message);
9634  }
9635 }
9636 
9637 // ---------------------------------------------------------------------------
9638 void __fastcall TInterface::DeleteMenuItemClick(TObject *Sender)
9639 {
9640  try
9641  {
9642  TrainController->LogEvent("DeleteMenuItemClick");
9643  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteMenuItemClick");
9644  // Level1Mode = TrackMode;
9645  // SetLevel1Mode(75);
9647  SetLevel2TrackMode(38);
9648  Utilities->CallLogPop(1193);
9649  }
9650  catch(const Exception &e)
9651  {
9652  ErrorLog(153, e.Message);
9653  }
9654 }
9655 // ---------------------------------------------------------------------------
9656 
9657 void __fastcall TInterface::SelectLengthsMenuItemClick(TObject *Sender)
9658 {
9659  try
9660  {
9661  TrainController->LogEvent("SelectLengthsMenuItemClick");
9662  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectLengthsMenuItemClick");
9663  TrackElementPanel->Visible = false;
9664  TrackLengthPanel->Visible = true;
9665  TrackLengthPanel->SetFocus();
9666  SelectLengthsFlag = true;
9667  InfoPanel->Visible = true;
9668  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values or leave blank for no change";
9670  {
9671  ShowMessage("Note: length value will apply to each element's track within the selection.\n\nThis message will not be shown again.");
9672  LengthWarningSentFlag = true;
9673  }
9674  DistanceBox->Text = "";
9675  SpeedLimitBox->Text = "";
9678  ResetChangedFileDataAndCaption(19, true); // true for NonPrefDirChangesMade
9679  Utilities->CallLogPop(1414);
9680  }
9681  catch(const Exception &e)
9682  {
9683  ErrorLog(154, e.Message);
9684  }
9685 }
9686 
9687 // ---------------------------------------------------------------------------
9688 
9689 void __fastcall TInterface::SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
9690 {
9691 /* SelectVector contains all the track elements (and inactive elements but don't need them), so create up to 4 PrefDir
9692  elements from each one, and add each into ConstructPrefDir, then when all added use ConsolidatePrefDirs to add to EveryPrefDir
9693 */
9694  try
9695  {
9696  TrainController->LogEvent("SelectBiDirPrefDirsMenuItemClick");
9697  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectBiDirPrefDirsMenuItemClick");
9699  bool FoundFlag = false;
9700  if(Track->SelectVector.empty())
9701  {
9702  Utilities->CallLogPop(1550);
9703  return;
9704  }
9705  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9706  {
9707  TTrackElement TE = Track->SelectVectorAt(14, x);
9708  int VecPos = Track->GetVectorPositionFromTrackMap(42, TE.HLoc, TE.VLoc, FoundFlag);
9709  if(FoundFlag)
9710  {
9711  if((TE.TrackType == Points) || (TE.TrackType == Bridge) || (TE.TrackType == Crossover)) // 2-track element
9712  {
9713  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
9715  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
9717  TPrefDirElement PE2(TE, TE.Link[2], 2, TE.Link[3], 3, VecPos);
9719  TPrefDirElement PE3(TE, TE.Link[3], 3, TE.Link[2], 2, VecPos);
9721  }
9722  else if((TE.TrackType == Simple) || (TE.TrackType == Buffers) || (TE.TrackType == SignalPost) || (TE.TrackType == Continuation) ||
9723  (TE.TrackType == GapJump) || (TE.TrackType == FootCrossing))
9724  // need to list these explicitly since inactive elements will still be 'found' if there is an active element
9725  // at the same position
9726  {
9727  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
9729  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
9731  }
9732  }
9733  }
9735  ResetChangedFileDataAndCaption(22, false);
9736  // RlyFile = false; - don't alter this just for PrefDir changes
9737  Level1Mode = BaseMode; // call this first to clear everything, then set PrefDir mode
9738  SetLevel1Mode(30);
9740  SetLevel1Mode(31); // calls Clearand... to display all PrefDirs
9741  Utilities->CallLogPop(1549);
9742  }
9743  catch(const Exception &e)
9744  {
9745  ErrorLog(155, e.Message);
9746  }
9747 }
9748 
9749 // ---------------------------------------------------------------------------
9750 void __fastcall TInterface::CancelSelectionMenuItemClick(TObject *Sender)
9751 {
9752  try
9753  {
9754  TrainController->LogEvent("CancelSelectionClick");
9755  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelSelectionClick");
9756  ClearandRebuildRailway(46); // to remove the selection outline
9757  SelectionValid = false;
9758  Track->CopyFlag = false;
9760  ResetSelectRect();
9761  if(Level1Mode == TrackMode)
9762  {
9763  SetLevel1Mode(76);
9765  SetLevel2TrackMode(39);
9766  }
9767  else if(Level1Mode == PrefDirMode)
9768  {
9769  SetLevel1Mode(32);
9770  }
9771  Utilities->CallLogPop(1413);
9772  }
9773  catch(const Exception &e)
9774  {
9775  ErrorLog(156, e.Message);
9776  }
9777 }
9778 
9779 // ---------------------------------------------------------------------------
9780 void __fastcall TInterface::LoadTimetableMenuItemClick(TObject *Sender)
9781 {
9782  try
9783  {
9784  TrainController->LogEvent("LoadTimetableMenuItemClick");
9785  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadTimetableMenuItemClick");
9786  TimetableDialog->Filter = "Timetable file (*.ttb)|*.ttb";
9787  // reset all message flags, stops them being given twice new at v2.4.0
9788  TrainController->SSHigh = false;
9789  TrainController->MRSHigh = false;
9790  TrainController->MRSLow = false;
9791  TrainController->MassHigh = false;
9792  TrainController->BFHigh = false;
9793  TrainController->BFLow = false;
9794  TrainController->PwrHigh = false;
9795  TrainController->SigSHigh = false;
9796  TrainController->SigSLow = false;
9797  if(TimetableDialog->Execute())
9798  {
9799  if(TimetableDialog->InitialDir != TPath::GetDirectoryName(TimetableDialog->FileName))//new at v2.6.0 to retain a new directory
9800  {
9801  TimetableDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
9802  SaveTTDialog->InitialDir = TPath::GetDirectoryName(TimetableDialog->FileName);
9803  }
9804  TrainController->LogEvent("LoadTimetable " + TimetableDialog->FileName);
9805  bool CheckLocationsExistInRailwayTrue = true;
9806  if(TrainController->TimetableIntegrityCheck(0, AnsiString(TimetableDialog->FileName).c_str(), true, CheckLocationsExistInRailwayTrue))
9807  // true for GiveMessages
9808  {
9809  Screen->Cursor = TCursor(-11); // Hourglass;
9810  std::ifstream TTBLFile(AnsiString(TimetableDialog->FileName).c_str(), std::ios_base::binary);
9811  if(TTBLFile.is_open())
9812  {
9813  bool SessionFileFalse = false;
9814  if(BuildTrainDataVectorForLoadFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue, SessionFileFalse)) // true for GiveMessages
9815  {
9816  SaveTempTimetableFile(0, TimetableDialog->FileName);
9817  } // don't need an 'else' as messages given in BuildTrainDataVectorForLoadFile
9818  }
9819  else
9820  {
9821  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
9822  }
9823  Screen->Cursor = TCursor(-2); // Arrow
9824  } // if(TimetableIntegrityCheck
9825  else
9826  ShowMessage("Timetable preliminary integrity check failed - unable to load");
9827  } // if(TimetableDialog->Execute())
9828  // else ShowMessage("Load Aborted");
9829  Utilities->CallLogPop(752);
9830  }
9831  catch(const Exception &e)
9832  {
9833  ErrorLog(34, e.Message);
9834  }
9835 }
9836 
9837 // ---------------------------------------------------------------------------
9838 void __fastcall TInterface::TakeSignallerControlMenuItemClick(TObject *Sender)
9839 {
9840  try
9841  {
9842  TrainController->LogEvent("SignallerControl1Click");
9843  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControl1Click");
9845  Train.SignallerStoppingFlag = false;
9846  Train.TrainMode = Signaller;
9847  if(Train.MaxRunningSpeed > Train.SignallerMaxSpeed)
9848  {
9849  Train.MaxRunningSpeed = Train.SignallerMaxSpeed;
9850  }
9851  if(Train.Stopped())
9852  Train.SignallerStopped = true; // condition added at v2.4.0 to allow for taking sig control of failed moving trains
9853  Train.CallingOnFlag = false; // in case was set, wouldn't start anyway if called on as SignallerStopped = true
9855  Train.PlotTrain(5, Display);
9856  AnsiString LocName = "";
9857  if(Train.LeadElement > -1)
9858  {
9859  LocName = Track->TrackElementAt(633, Train.LeadElement).ActiveTrackElementName;
9860  }
9861  if((LocName == "") && (Train.MidElement > -1))
9862  {
9863  LocName = Track->TrackElementAt(634, Train.MidElement).ActiveTrackElementName;
9864  }
9865 
9866  // store the value that allow restoration of tt control or not - RestoreTimetableLocation
9867  if(Train.StoppedAtLocation && (LocName != ""))
9868  {
9869  Train.RestoreTimetableLocation = LocName;
9870  }
9871  else
9872  {
9873  Train.RestoreTimetableLocation = "";
9874  }
9875 
9876  // check whether need to offer 'pass red signal'
9877  if(!Train.StoppedAtSignal && Train.StoppedAtLocation)
9878  {
9879  int NextElementPosition = Track->TrackElementAt(775, Train.LeadElement).Conn[Train.LeadExitPos];
9880  int NextEntryPos = Track->TrackElementAt(776, Train.LeadElement).ConnLinkPos[Train.LeadExitPos];
9881  if((NextElementPosition > -1) && (NextEntryPos > -1))
9882  {
9883  if((Track->TrackElementAt(777, NextElementPosition).Config[Track->GetNonPointsOppositeLinkPos(NextEntryPos)] == Signal) &&
9884  (Track->TrackElementAt(778, NextElementPosition).Attribute == 0))
9885  { // set both StoppedAtLocation & StoppedAtSignal, so that 'pass red signal' is offered in popup menu rather than move
9886  // forwards, but don't change the background colour so still shows as stopped at location
9887  Train.StoppedAtSignal = true;
9888  }
9889  }
9890  }
9891  // find element ID if no locname
9892  if((LocName == "") && Train.LeadElement > -1)
9893  {
9894  LocName = Track->TrackElementAt(635, Train.LeadElement).ElementID;
9895  }
9896  if((LocName == "") && (Train.MidElement > -1))
9897  {
9898  LocName = Track->TrackElementAt(636, Train.MidElement).ElementID;
9899  }
9900  Train.LogAction(0, Train.HeadCode, "", TakeSignallerControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9901  Utilities->CallLogPop(1772);
9902  }
9903  catch(const Exception &e)
9904  {
9905  ErrorLog(157, e.Message);
9906  }
9907 }
9908 
9909 // ---------------------------------------------------------------------------
9910 
9911 void __fastcall TInterface::TimetableControlMenuItemClick(TObject *Sender)
9912 {
9913  try
9914  {
9915  TrainController->LogEvent("TimetableControlMenuItemClick");
9916  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableControlMenuItemClick");
9918  Train.SignallerStoppingFlag = false;
9919  Train.TrainMode = Timetable;
9920  Train.SignallerStopped = false;
9921  Train.StoppedAfterSPAD = false;
9922  Train.SPADFlag = false;
9925 // red headcode[0]
9926  Train.PlotTrain(6, Display);
9927  AnsiString LocName = "";
9928  if(Train.LeadElement > -1)
9929  {
9930  LocName = Track->TrackElementAt(645, Train.LeadElement).ActiveTrackElementName;
9931  }
9932  if((LocName == "") && (Train.MidElement > -1))
9933  {
9934  LocName = Track->TrackElementAt(647, Train.MidElement).ActiveTrackElementName;
9935  }
9936  if((LocName == "") && Train.LeadElement > -1)
9937  {
9938  LocName = Track->TrackElementAt(646, Train.LeadElement).ElementID;
9939  }
9940  if((LocName == "") && (Train.MidElement > -1))
9941  {
9942  LocName = Track->TrackElementAt(648, Train.MidElement).ElementID;
9943  }
9944  if((Train.ActionVectorEntryPtr->LocationType == AtLocation) && (LocName == Train.ActionVectorEntryPtr->LocationName))
9945  {
9946  Train.StoppedAtLocation = true;
9947  Train.StoppedAtSignal = false; //added at v2.7.0 as if had been stopped at signal before tt control restored then background colour would change to normal when signal cleared even when not due to depart
9948  Train.LastActionTime = TrainController->TTClockTime; // by itself this only affects trains that have still to arrive, if waiting to
9949  // depart the departure time & TRS time have already been calculated so need to
9950  // force a recalculation - see below
9951  Train.DepartureTimeSet = false; // force it to be recalculated based on new LastActionTime (if waiting to arrive this is false anyway)
9952  if(!Train.TrainFailed)
9953  {
9955  }
9956  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9957  if((Train.ActionVectorEntryPtr->FormatType == TimeLoc) && (Train.ActionVectorEntryPtr->ArrivalTime >= TDateTime(0)))
9958  { // Timetable indicates that train still waiting to arrive for a TimeLoc arrival so send message and mark as arrived
9959  Train.LogAction(28, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
9960  Train.ActionVectorEntryPtr++; // advance pointer past arrival //added at v1.2.0
9961  }
9962  else if((Train.ActionVectorEntryPtr->FormatType == TimeTimeLoc) && !(Train.TimeTimeLocArrived))
9963  { // Timetable indicates that train still waiting to arrive for a TimeTimeLoc arrival so send message and mark as arrived
9964  Train.LogAction(29, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
9965  Train.TimeTimeLocArrived = true;
9966  // NB: No need for 'Train.ActionVectorEntryPtr++' because still to act on the departure time
9967  }
9968  }
9969  else
9970  {
9971  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas' error
9972  int NextEntryPos = -1; // ---ditto---
9973  if(Train.LeadElement > -1) // ---ditto---
9974  { // ---ditto---
9975  NextElementPos = Track->TrackElementAt(658, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
9976  NextEntryPos = Track->TrackElementAt(659, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
9977  } // ---ditto---
9978  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9979  if(!Train.TrainFailed)
9980  {
9981  Train.PlotTrainWithNewBackgroundColour(31, clNormalBackground, Display); // to remove other background if was present, moved from
9982  } // within Train.AbleToMove at v2.4.0 to cancel signal stop background
9983  if(Train.AbleToMove(1)) // if has no power
9984  {
9985  Train.EntrySpeed = 0; // moved from below for v1.3.2 after Carwyn Thomas error
9986  Train.EntryTime = TrainController->TTClockTime; // ---Ditto---
9987  Train.FirstHalfMove = true; // ---Ditto---
9988  if((NextElementPos > -1) && (NextEntryPos > -1)) // changed from if(NextElementPos >= 0) as above
9989  {
9990  // Train.EntrySpeed = 0;
9991  // Train.EntryTime = TrainController->TTClockTime;
9992  // Train.FirstHalfMove = true;
9993  Train.SetTrainMovementValues(15, NextElementPos, NextEntryPos);
9994  }
9995  // else follow the continuations //added these 3 conditions for v1.3.2 after Carwyn Thomas error
9996  else if((Train.LeadElement > -1) && (Track->TrackElementAt(894, Train.LeadElement).TrackType == Continuation))
9997  {
9998  Train.SetTrainMovementValues(21, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
9999  }
10000  else if((Train.MidElement > -1) && (Track->TrackElementAt(895, Train.MidElement).TrackType == Continuation))
10001  {
10002  Train.SetTrainMovementValues(22, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
10003  }
10004  else if((Train.LagElement > -1) && (Track->TrackElementAt(896, Train.LagElement).TrackType == Continuation))
10005  {
10006  Train.SetTrainMovementValues(23, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
10007  }
10008  }
10009  else if(Train.StoppedAtSignal)
10010  {
10011  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10012  if(!Train.TrainFailed)
10013  {
10015  }
10016  // TrainController->LogActionError(42, Train.HeadCode, "", SignalHold, Track->TrackElementAt(757, NextElementPos).ElementID);
10017  }
10018  }
10019  Train.LogAction(1, Train.HeadCode, "", RestoreTimetableControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10020  Utilities->CallLogPop(1195);
10021  }
10022  catch(const Exception &e)
10023  {
10024  ErrorLog(158, e.Message);
10025  }
10026 }
10027 
10028 // ---------------------------------------------------------------------------
10029 
10030 void __fastcall TInterface::ChangeDirectionMenuItemClick(TObject *Sender)
10031 {
10032  try
10033  {
10034  TrainController->LogEvent("ChangeDirectionMenuItemClick");
10035  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ChangeDirectionMenuItemClick");
10037  Train.SignallerStoppingFlag = false;
10038  Train.SignallerChangeTrainDirection(0); // this unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd
10039  Train.SignallerStopped = true;
10040  AnsiString LocName = "";
10041  if(Train.LeadElement > -1)
10042  {
10043  LocName = Track->TrackElementAt(637, Train.LeadElement).ActiveTrackElementName;
10044  }
10045  if((LocName == "") && (Train.MidElement > -1))
10046  {
10047  LocName = Track->TrackElementAt(638, Train.MidElement).ActiveTrackElementName;
10048  }
10049  if((LocName == "") && Train.LeadElement > -1)
10050  {
10051  LocName = Track->TrackElementAt(639, Train.LeadElement).ElementID;
10052  }
10053  if((LocName == "") && (Train.MidElement > -1))
10054  {
10055  LocName = Track->TrackElementAt(640, Train.MidElement).ElementID;
10056  }
10057  Train.LogAction(2, Train.HeadCode, "", SignallerChangeDirection, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10058  Utilities->CallLogPop(1196);
10059  }
10060  catch(const Exception &e)
10061  {
10062  ErrorLog(159, e.Message);
10063  }
10064 }
10065 // ---------------------------------------------------------------------------
10066 
10067 void __fastcall TInterface::MoveForwardsMenuItemClick(TObject *Sender)
10068 {
10069  try
10070  {
10071  TrainController->LogEvent("MoveForwardsMenuItemClick");
10072  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveForwardsMenuItemClick");
10074  Train.SignallerStoppingFlag = false;
10075  if(!Train.AbleToMove(2))
10076  { // shouldn't be here as when unable to move MoveForwards shouldn't be enabled, but leave in as a precaution
10077  Utilities->CallLogPop(1197);
10078  return;
10079  }
10080  Train.SignallerStopped = false;
10081  Train.StoppedAfterSPAD = false; // in case had been set
10082  Train.SPADFlag = false;
10083  Train.StoppedAtLocation = false; // may not have been set but reset anyway
10084  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10086  Train.EntrySpeed = 0;
10088  Train.FirstHalfMove = true;
10089  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas error
10090  int NextEntryPos = -1; // ---ditto---
10091  if(Train.LeadElement > -1) // ---ditto---
10092  { // ---ditto---
10093  NextElementPos = Track->TrackElementAt(652, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
10094  NextEntryPos = Track->TrackElementAt(657, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
10095  } // ---ditto---
10096  if((NextElementPos > -1) && (NextEntryPos > -1))
10097  {
10098  Train.SetTrainMovementValues(14, NextElementPos, NextEntryPos); // NextElement is the element to be entered
10099  }
10100  // else follow the continuations
10101  else if((Train.LeadElement > -1) && (Track->TrackElementAt(784, Train.LeadElement).TrackType == Continuation))
10102  {
10103  Train.SetTrainMovementValues(17, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
10104  }
10105  else if((Train.MidElement > -1) && (Track->TrackElementAt(785, Train.MidElement).TrackType == Continuation))
10106  {
10107  Train.SetTrainMovementValues(18, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
10108  }
10109  else if((Train.LagElement > -1) && (Track->TrackElementAt(786, Train.LagElement).TrackType == Continuation))
10110  {
10111  Train.SetTrainMovementValues(19, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
10112  }
10113  Train.LogAction(3, Train.HeadCode, "", SignallerMoveForwards, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10114  Utilities->CallLogPop(1198);
10115  }
10116  catch(const Exception &e)
10117  {
10118  ErrorLog(160, e.Message);
10119  }
10120 }
10121 // ---------------------------------------------------------------------------
10122 
10123 void __fastcall TInterface::SignallerJoinedByMenuItemClick(TObject *Sender)
10124 { // new at v2.4.0
10125  try
10126  {
10127  TrainController->LogEvent("JoinedByMenuItemClick");
10128  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",JoinedByMenuItemClick");
10129  TTrain *TrainToBeJoinedBy;
10131  if(ThisTrain.IsThereAnAdjacentTrain(1, TrainToBeJoinedBy)) // this must come before both powers zero check in order to set a valid TrainToBeJoinedBy
10132  {
10133  if(TrainToBeJoinedBy->TrainMode != Signaller)
10134  {
10135  TrainController->StopTTClockMessage(91, "Adjacent train must be under signaller control in order to join");
10136  Utilities->CallLogPop(2156);
10137  return;
10138  }
10139  // here if there is an adjacent train under signaller control
10140  if((TrainToBeJoinedBy->PowerAtRail < 1) && (ThisTrain.PowerAtRail < 1))
10141  {
10142  ShowMessage("Can't join two trains when both are without power");
10143  Utilities->CallLogPop(2157);
10144  return;
10145  }
10146  AnsiString TrainToBeJoinedByHeadCode = TrainToBeJoinedBy->HeadCode;
10147  // set new values for mass etc
10148  double OtherBrakeForce = TrainToBeJoinedBy->MaxBrakeRate * TrainToBeJoinedBy->Mass;
10149  double OwnBrakeForce = ThisTrain.MaxBrakeRate * ThisTrain.Mass;
10150  double CombinedBrakeRate = (OtherBrakeForce + OwnBrakeForce) / (TrainToBeJoinedBy->Mass + ThisTrain.Mass);
10151  ThisTrain.Mass += TrainToBeJoinedBy->Mass;
10152  ThisTrain.MaxBrakeRate = CombinedBrakeRate;
10153  ThisTrain.PowerAtRail += TrainToBeJoinedBy->PowerAtRail;
10154  ThisTrain.AValue = sqrt(2 * ThisTrain.PowerAtRail / ThisTrain.Mass);
10155 
10156  TrainToBeJoinedBy->TrainGone = true; // this will cause other train to be deleted
10157  TrainToBeJoinedBy->JoinedOtherTrainFlag = true;
10158  AnsiString LocName = "";
10159  if(ThisTrain.LeadElement > -1)
10160  {
10161  LocName = Track->TrackElementAt(979, ThisTrain.LeadElement).ActiveTrackElementName;
10162  }
10163  if((LocName == "") && (ThisTrain.MidElement > -1))
10164  {
10165  LocName = Track->TrackElementAt(980, ThisTrain.MidElement).ActiveTrackElementName;
10166  }
10167  if((LocName == "") && ThisTrain.LeadElement > -1)
10168  {
10169  LocName = Track->TrackElementAt(981, ThisTrain.LeadElement).ElementID;
10170  }
10171  if((LocName == "") && (ThisTrain.MidElement > -1))
10172  {
10173  LocName = Track->TrackElementAt(982, ThisTrain.MidElement).ElementID;
10174  }
10175  ThisTrain.StoppedWithoutPower = true;
10176  if(ThisTrain.PowerAtRail >= 1)
10177  {
10178  ThisTrain.StoppedWithoutPower = false;
10179  }
10180  ThisTrain.TrainFailed = false; // if had failed then no longer failed, even if joining train has no power
10181  if(!ThisTrain.StoppedAtLocation)
10182  {
10183  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10185  }
10186  else
10187  {
10188  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10190  }
10191  ThisTrain.SignallerStopped = true; // maybe as well as stopped without power, thought that takes precedence in floating window
10192  ThisTrain.LogAction(34, ThisTrain.HeadCode, TrainToBeJoinedBy->HeadCode, SignallerJoin, LocName, TDateTime(0), false); // TDateTime isn't used
10193  ThisTrain.ZeroPowerNoFrontSplitMessage = false; // added at v2.4.0, no need to include TrainToBeJoinedBy as that will be removed
10194  ThisTrain.ZeroPowerNoRearSplitMessage = false;
10195  ThisTrain.FailedTrainNoFinishJoinMessage = false;
10196  ThisTrain.ZeroPowerNoJoinedByMessage = false;
10197  ThisTrain.ZeroPowerNoCDTMessage = false;
10198  ThisTrain.ZeroPowerNoNewServiceMessage = false;
10200  ThisTrain.ZeroPowerNoRepeatShuttleMessage = false;
10202  Utilities->CallLogPop(2158);
10203  }
10204  }
10205  catch(const Exception &e)
10206  {
10207  ErrorLog(207, e.Message);
10208  }
10209 }
10210 // ---------------------------------------------------------------------------
10211 
10212 void __fastcall TInterface::RepairFailedTrainMenuItemClick(TObject *Sender)
10213 { // added at v2.4.0
10214  try
10215  {
10216  TrainController->LogEvent("RepairFailedTrainMenuItemClick");
10217  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedTrainMenuItemClick");
10219  Train.TrainFailed = false;
10220  Train.StoppedWithoutPower = false;
10221  Train.SignallerStopped = true;
10222  if(!Train.StoppedAtLocation)
10223  {
10224  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10226  }
10227  else
10228  {
10229  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10231  }
10232  Train.PowerAtRail = Train.OriginalPowerAtRail; // recover from original value, new at v2.4.0
10233  Train.AValue = sqrt(2 * Train.PowerAtRail / Train.Mass);
10234  Train.SetTrainMovementValues(24, Train.LeadElement, Train.LeadEntryPos);
10235  AnsiString LocName = "";
10236  if(Train.LeadElement > -1)
10237  {
10238  LocName = Track->TrackElementAt(983, Train.LeadElement).ActiveTrackElementName;
10239  }
10240  if((LocName == "") && (Train.MidElement > -1))
10241  {
10242  LocName = Track->TrackElementAt(984, Train.MidElement).ActiveTrackElementName;
10243  }
10244  if((LocName == "") && Train.LeadElement > -1)
10245  {
10246  LocName = Track->TrackElementAt(985, Train.LeadElement).ElementID;
10247  }
10248  if((LocName == "") && (Train.MidElement > -1))
10249  {
10250  LocName = Track->TrackElementAt(986, Train.MidElement).ElementID;
10251  }
10252  Train.LogAction(35, Train.HeadCode, "", RepairFailedTrain, LocName, TrainController->TTClockTime, false); // false for no warning
10253  Train.ZeroPowerNoFrontSplitMessage = false;
10254  Train.ZeroPowerNoRearSplitMessage = false;
10255  Train.FailedTrainNoFinishJoinMessage = false;
10256  Train.ZeroPowerNoJoinedByMessage = false;
10257  Train.ZeroPowerNoCDTMessage = false;
10258  Train.ZeroPowerNoNewServiceMessage = false;
10260  Train.ZeroPowerNoRepeatShuttleMessage = false;
10262  Utilities->CallLogPop(2159);
10263  }
10264  catch(const Exception &e)
10265  {
10266  ErrorLog(208, e.Message);
10267  }
10268 }
10269 
10270 // ---------------------------------------------------------------------------
10271 
10272 void __fastcall TInterface::SignallerControlStopMenuItemClick(TObject *Sender)
10273 {
10274  try
10275  {
10276  TrainController->LogEvent("SignallerControlStopMenuItemClick");
10277  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControlStopMenuItemClick");
10280  if(Train.LeadElement > -1)
10281  {
10282  if(Track->TrackElementAt(787, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
10283  {
10284  Train.SignallerStoppingFlag = true;
10285  Train.SignallerStopBrakeRate = 0;
10286  Train.LogAction(24, Train.HeadCode, "", SignallerControlStop, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10287  }
10288  else
10290  }
10291  else
10293  Utilities->CallLogPop(1553);
10294  }
10295  catch(const Exception &e)
10296  {
10297  ErrorLog(161, e.Message);
10298  }
10299 }
10300 
10301 // ---------------------------------------------------------------------------
10302 void __fastcall TInterface::PassRedSignalMenuItemClick(TObject *Sender)
10303 {
10304  try
10305  {
10306  TrainController->LogEvent("PassRedSignalMenuItemClick");
10307  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PassRedSignalMenuItemClick");
10309  Train.SignallerStoppingFlag = false;
10310  int NextElementPos = Track->TrackElementAt(712, Train.LeadElement).Conn[Train.LeadExitPos];
10311  if(NextElementPos < 0)
10312  {
10313  throw Exception("Error, no element in front in PassRedSignalMenuItemClick");
10314  }
10315  TTrackElement &TrackElement = Track->TrackElementAt(653, NextElementPos);
10316 /* drop this error as may be some circumstances where behind a signal in sig mode but not stopped at signal
10317  if(!Train.StoppedAtSignal)
10318  {
10319  throw Exception("Error, not StoppedAtSignal in PassRedSignalMenuItemClick");
10320  }
10321 */
10322  if(TrackElement.TrackType != SignalPost)
10323  {
10324  throw Exception("Error, next element not a signal type in PassRedSignalMenuItemClick");
10325  }
10326  Train.SignallerStopped = false;
10327  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
10328  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
10329  // since no need to alert the user
10330  Train.StoppedAfterSPAD = false; // in case had been set
10331  Train.SPADFlag = false;
10332  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10334  Train.AllowedToPassRedSignal = true;
10335  Train.LogAction(4, Train.HeadCode, "", SignallerPassRedSignal, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10336  Utilities->CallLogPop(1199);
10337  }
10338  catch(const Exception &e)
10339  {
10340  ErrorLog(162, e.Message);
10341  }
10342 }
10343 // ---------------------------------------------------------------------------
10344 
10345 void __fastcall TInterface::StepForwardMenuItemClick(TObject *Sender)
10346 {
10347  try
10348  {
10349  TrainController->LogEvent("StepForwardMenuItemClick");
10350  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",StepForwardMenuItemClick");
10352  Train.SignallerStoppingFlag = false;
10353  Train.SignallerStopped = false;
10354  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
10355  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
10356  // since no need to alert the user
10357  Train.StoppedAfterSPAD = false; // in case had been set
10358  Train.SPADFlag = false;
10359  Train.StepForwardFlag = true;
10360  Train.AllowedToPassRedSignal = true; // in case at a signal, will clear when half-way into next element whether a signal or not
10361  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10363  Train.LogAction(32, Train.HeadCode, "", SignallerStepForward, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10364  int NextElementPos = -1;
10365 // addition for v1.3.2 due to Carwyn Thomas error: can't select StepForwardMenuItem if exiting at a continuation but leave this in anyway
10366  int NextEntryPos = -1; // ---ditto---
10367  if(Train.LeadElement > -1) // ---ditto---
10368  { // ---ditto---
10369  NextElementPos = Track->TrackElementAt(804, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
10370  NextEntryPos = Track->TrackElementAt(805, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
10371  } // ---ditto---
10372  if((NextElementPos > -1) && (NextEntryPos > -1))
10373  { // call this after StepForwardFlag set
10374  Train.EntrySpeed = 0;
10376  Train.FirstHalfMove = true;
10377  Train.SetTrainMovementValues(20, NextElementPos, NextEntryPos); // NextElement is the element to be entered
10378  }
10379  Utilities->CallLogPop(1800);
10380  }
10381  catch(const Exception &e)
10382  {
10383  ErrorLog(163, e.Message);
10384  }
10385 }
10386 
10387 // ---------------------------------------------------------------------------
10388 
10389 void __fastcall TInterface::RemoveTrainMenuItemClick(TObject *Sender)
10390 {
10391  try
10392  {
10393  TrainController->LogEvent("RemoveTrainMenuItemClick");
10394  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RemoveTrainMenuItemClick");
10396  if((!Train.Derailed) && (!Train.Crashed))
10397  {
10398  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
10400  UnicodeString Message = UnicodeString(Train.HeadCode) + " will be removed from the railway - proceed?";
10401  int button = Application->MessageBox(Message.c_str(), L"Please confirm", MB_YESNO);
10402  TrainController->BaseTime = TDateTime::CurrentDateTime();
10404  if(button == IDNO)
10405  {
10406  Utilities->CallLogPop(1801);
10407  return;
10408  }
10409  }
10410  Train.SignallerStoppingFlag = false;
10411  Train.TrainGone = true; // will be removed by TTrainController::Operate
10412  Train.SignallerRemoved = true;
10413  Train.TrainDataEntryPtr->TrainOperatingDataVector.at(Train.RepeatNumber).RunningEntry = Exited;
10414  AnsiString LocName = "";
10415  if(Train.LeadElement > -1)
10416  {
10417  LocName = Track->TrackElementAt(641, Train.LeadElement).ActiveTrackElementName;
10418  }
10419  if((LocName == "") && (Train.MidElement > -1))
10420  {
10421  LocName = Track->TrackElementAt(642, Train.MidElement).ActiveTrackElementName;
10422  }
10423  if((LocName == "") && Train.LeadElement > -1)
10424  {
10425  LocName = Track->TrackElementAt(643, Train.LeadElement).ElementID;
10426  }
10427  if((LocName == "") && (Train.MidElement > -1))
10428  {
10429  LocName = Track->TrackElementAt(644, Train.MidElement).ElementID;
10430  }
10431  TTrackElement *TrackElementPtr;
10432  int RouteNumber;
10433  TAllRoutes::TRouteType RouteType;
10434  if(Train.LeadElement > -1)
10435  {
10436  TrackElementPtr = &(Track->TrackElementAt(673, Train.LeadElement));
10437  // remove TrainIDs from track element, added at v2.4.0
10438  if(TrackElementPtr->TrackType == Bridge)
10439  {
10440  if(Train.LeadExitPos > 1)
10441  {
10442  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
10443  }
10444  else
10445  {
10446  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
10447  }
10448  }
10449  else
10450  {
10451  TrackElementPtr->TrainIDOnElement = -1;
10452  }
10453  // reset any CallingOnSet flags for signals, if facing wrong way doesn't matter, shouldn't be set anyay
10454  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10455  {
10456  TrackElementPtr->CallingOnSet = false;
10457  Track->PlotSignal(6, *TrackElementPtr, Display);
10458  }
10459 // [added at v1.3.0] here check if on an automatic signals route and if so reset signals for the entire route from the
10460 // start of the route - after the train has been removed, use LeadElement and also MidElement (if no autosigs route at LeadElement) just to be sure
10461  RouteType = AllRoutes->GetRouteTypeAndNumber(27, Train.LeadElement, Train.LeadEntryPos, RouteNumber);
10462  if(RouteType == TAllRoutes::AutoSigsRoute)
10463  {
10466  }
10467 // end of addition
10468 
10469 //erase a stub route if there is one, added at v2.6.1
10470 //first element of route is immediately in front of the train
10471  if(Train.LeadExitPos >= 0)
10472  {
10473  TTrackElement LeadTrackElement = Track->TrackElementAt(1013, Train.LeadElement);
10474  int FirstRouteElementVecPos = LeadTrackElement.Conn[Train.LeadExitPos];
10475  int FirstRouteLinkPos = LeadTrackElement.ConnLinkPos[Train.LeadExitPos];
10476  RouteType = AllRoutes->GetRouteTypeAndNumber(39, FirstRouteElementVecPos, FirstRouteLinkPos, RouteNumber);
10477  if(RouteType == TAllRoutes::NotAutoSigsRoute) //red or green route, if no route then ignore
10478  {
10479  TOneRoute &OR = AllRoutes->GetModifiableRouteAt(30, RouteNumber);
10480  TTrackElement TE = Track->TrackElementAt(1014, FirstRouteElementVecPos);
10481  if((TE.TrackType != SignalPost) && (TE.TrackType != Continuation))//all autosigs routes have signalpost or continuation at 0 so they are automatically excluded
10482  {
10483  while(OR.PrefDirSize() > 0) //remove the route up to but not including the next facing signal, in case a route extends to another signal
10484  {
10485  TPrefDirElement PDE = OR.GetFixedPrefDirElementAt(249, 0); //these will change at each element removal because OR is a reference to the real route
10486  int TVPos2 = PDE.GetTrackVectorPosition();
10487  TTrackElement TE2 = Track->TrackElementAt(1015, TVPos2);
10488  if(Track->TrackElementAt(1016, PDE.GetTrackVectorPosition()).Config[PDE.GetXLinkPos()] != Signal)
10489  {
10490  AllRoutes->RemoveRouteElement(24, TE2.HLoc, TE2.VLoc, PDE.GetELink());
10491  }
10492  else
10493  {
10494  break;
10495  }
10496  }
10497  AllRoutes->RebuildRailwayFlag = true;
10498  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to replot without stub route
10499  }
10500  }
10501  }
10502 //end of stub route removal addition
10503  }
10504  if(Train.MidElement > -1)
10505  {
10506  TrackElementPtr = &(Track->TrackElementAt(674, Train.MidElement));
10507  // remove TrainIDs from track element, added at v2.4.0
10508  if(TrackElementPtr->TrackType == Bridge)
10509  {
10510  if(Train.MidExitPos > 1)
10511  {
10512  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
10513  }
10514  else
10515  {
10516  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
10517  }
10518  }
10519  else
10520  {
10521  TrackElementPtr->TrainIDOnElement = -1;
10522  }
10523  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10524  {
10525  TrackElementPtr->CallingOnSet = false;
10526  Track->PlotSignal(7, *TrackElementPtr, Display);
10527  }
10528 // [added at v1.3.0 as above]
10530  {
10531  RouteType = AllRoutes->GetRouteTypeAndNumber(28, Train.MidElement, Train.MidEntryPos, RouteNumber);
10532  if(RouteType == TAllRoutes::AutoSigsRoute)
10533  {
10536  }
10537  }
10538 // end of addition
10539  }
10540  if(Train.LeadElement > -1)
10541  // addition for v1.3.2 after Carwyn Thomas fault reported 24/05/15 - need to check if exiting at continuation (LeadElement == -1) as if so fails at next line
10542  {
10543  if(Track->TrackElementAt(675, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
10544  {
10545  TrackElementPtr = &(Track->TrackElementAt(676, Track->TrackElementAt(677, Train.LeadElement).Conn[Train.LeadExitPos]));
10546  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10547  {
10548  TrackElementPtr->CallingOnSet = false;
10549  Track->PlotSignal(8, *TrackElementPtr, Display);
10550  }
10551  }
10552  }
10553  Train.LogAction(5, Train.HeadCode, "", RemoveTrain, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10554  if(Train.ActionVectorEntryPtr->Command != "Frh") // if remaining at location no point in sending 'failed to terminate' message
10555  {
10556  Train.SendMissedActionLogs(0, -1, Train.ActionVectorEntryPtr); // -1 is a marker for send messages for all remaining
10557  } // entries, including Fer if present
10558  Utilities->CallLogPop(1200);
10559  }
10560  catch(const Exception &e)
10561  {
10562  ErrorLog(164, e.Message);
10563  }
10564 }
10565 
10566 // ---------------------------------------------------------------------------
10567 
10568 void __fastcall TInterface::ErrorButtonClick(TObject *Sender)
10569  // to terminate after error message given
10570 {
10571  ErrorMessage->Visible = false;
10572  ErrorMessageStoreImage->Visible = false;
10573  ErrorButton->Visible = false;
10574  Display->GetImage()->Visible = true;
10575  Application->Terminate();
10576 }
10577 
10578 // ---------------------------------------------------------------------------
10579 void __fastcall TInterface::PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
10580 {
10581  try
10582  {
10583  TrainController->LogEvent("PerformancePanelLabelStartDrag");
10584  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelLabelStartDrag");
10585  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
10586  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
10587  Utilities->CallLogPop(1202);
10588  }
10589  catch(const Exception &e)
10590  {
10591  ErrorLog(165, e.Message);
10592  }
10593 }
10594 // ---------------------------------------------------------------------------
10595 
10596 void __fastcall TInterface::FormClose(TObject *Sender, TCloseAction &Action)
10597 {
10598  try
10599  {
10600  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FormClose");
10602  {
10603  UnicodeString MessageStr =
10604  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
10605  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
10606  if(button == IDNO)
10607  {
10608  Action = caNone; // prevents form & application from closing
10609  Utilities->CallLogPop(1712);
10610  return;
10611  }
10612  }
10614  {
10615  UnicodeString MessStr = "";
10617  {
10618  MessStr = UnicodeString("The railway and the timetable have both changed, exit without saving either?");
10619  }
10620  else if(FileChangedFlag)
10621  {
10622  MessStr = UnicodeString("The railway has changed, exit without saving?");
10623  }
10624  else
10625  {
10626  MessStr = UnicodeString("The timetable has changed, exit without saving?");
10627  }
10628  int button = Application->MessageBox(MessStr.c_str(), L"Please confirm", MB_YESNO);
10629  if(button == IDNO)
10630  {
10631  Action = caNone; // prevents form & application from closing
10632  Utilities->CallLogPop(1133);
10633  return;
10634  }
10635  }
10636 
10637  if(Level1Mode == OperMode)
10638  {
10640  {
10641  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
10642  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
10644  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
10645  TrainController->BaseTime = TDateTime::CurrentDateTime();
10647  if(button == IDNO)
10648  {
10649  Action = caNone; // prevents form & application from closing
10650  Utilities->CallLogPop(969);
10651  return;
10652  }
10653  }
10655  Utilities->PerformanceFile.close();
10656  }
10657  if((TempTTFileName != "") && FileExists(TempTTFileName))
10658  {
10659  DeleteFile(TempTTFileName);
10660  }
10661  Utilities->CallLogPop(971);
10662  }
10663  catch(const Exception &e)
10664  {
10665  ErrorLog(166, e.Message);
10666  }
10667 }
10668 
10669 // ---------------------------------------------------------------------------
10670 
10671 void __fastcall TInterface::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
10672 {
10673 // TrainController->LogEvent("FormKeyDown," + AnsiString(Key));
10674 // drop event log as have too many spurious entries
10675  try
10676  {
10677  if((Shift.Contains(ssAlt)) && (Shift.Contains(ssCtrl)))
10678  {
10679  if(Key == '2')
10680  {
10681  if(CallLogTickerLabel->Visible)
10682  {
10683  CallLogTickerLabel->Visible = false;
10684  }
10685  else
10686  {
10687  CallLogTickerLabel->Visible = true;
10688  }
10689  }
10690  else if(Key == '3')
10691  {
10692  if(DevelopmentPanel->Visible)
10693  {
10694  DevelopmentPanel->Visible = false;
10695  }
10696  else
10697  {
10698  DevelopmentPanel->Visible = true;
10699  DevelopmentPanel->BringToFront();
10700  }
10701  }
10702  else if(Key == '4')
10703  {
10704  TestFunction();
10705  }
10706  else if(Key == '5')
10707  {
10708  TMsgDlgButtons Buttons;
10709  Buttons << mbYes << mbNo;
10710  if(MessageDlg("Do you wish to allow facing signals next to bridges? If so please be aware that routes cannot be truncated to these signals.", mtWarning, Buttons, 0) == mrYes)
10711  {
10713  }
10714  else
10715  {
10717  }
10718  }
10719  }
10720  else if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10721  {
10722  CtrlKey = true;
10723  }
10724  else if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
10725  {
10726  ShiftKey = true;
10727  }
10728 
10729 // below added at v1.3.0 to allow keyboard scrolling as well as mouse button scrolling - see user suggestion on Features & Requests forum 30/09/12
10730 // the NonCTRLOrSHIFTKeyUpFlag prevents repeated viewpoint movements without keys being re-pressed
10731 // note that use the OnKeyDown event rather than OnKeyPress as suggested by the user so that the CTRL & SHIFT keys can be taken into account
10732 
10733 //at v2.4.2 the flag changed to LastNonCtrlOrShiftKeyDown to make condition specific to last key, because when a message given the key up event
10734 //is not seen as the form does not have focus, so with the flag no shortcut key will work on the first press, with this only the same shortcut key
10735 //won't work on first press and that is less likely to be used a second time on either side of the message
10736 
10737  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
10738  {
10739  if(LastNonCtrlOrShiftKeyDown == Key) //same key still down rejected
10740  {
10741  return;
10742  }
10743  else
10744  {
10746  }
10747  }
10748 
10749  if(Key == VK_UP)
10750  {
10751  if(ScreenUpButton->Enabled)
10752  ScreenUpButton->Click();
10753  }
10754  else if(Key == VK_DOWN)
10755  {
10756  if(ScreenDownButton->Enabled)
10757  ScreenDownButton->Click();
10758  }
10759  else if(Key == VK_LEFT)
10760  {
10761  if(ScreenLeftButton->Enabled)
10762  ScreenLeftButton->Click();
10763  }
10764  else if(Key == VK_RIGHT)
10765  {
10766  if(ScreenRightButton->Enabled)
10767  ScreenRightButton->Click();
10768  }
10769  else if(Key == VK_HOME)
10770  {
10771  if(HomeButton->Enabled)
10772  HomeButton->Click();
10773  }
10774 // end of 1.3.0 addition
10775  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
10776  {
10777  if(ZoomButton->Enabled)
10778  ZoomButton->Click();
10779  }
10780  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
10781  {
10782  if(ZoomButton->Enabled)
10783  ZoomButton->Click();
10784  }
10785 
10786 //below added for v2.4.2 to add more keyboard shortcuts
10787  if(DistanceBox->Focused() || SpeedLimitBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() || SpeedEditBox2->Focused()
10788  || MTBFEditBox->Focused() || LocationNameTextBox->Focused() || TextBox->Focused() || PowerEditBox->Focused() || SpeedEditBox->Focused()
10789  || AddSubMinsBox->Focused() || OneEntryTimetableMemo->Focused())
10790  {// prevent letter keys interfering when these boxes have focus - many are mutually exclusive but include them all
10791  return;
10792  }
10793 
10794  if(Shift.Contains(ssShift) && !Shift.Contains(ssAlt) && !Shift.Contains(ssCtrl) && NewHomeButton->Enabled && NewHomeButton->Visible)
10795  {
10796  if(Level1Mode != TimetableMode && (Key == 'H' || Key == 'h'))//TimetablePanel uses Shift H too so disable this when it's in use
10797  {
10798  NewHomeButton->Click();
10799  }
10800  }
10801 
10802 //Operating panel
10803  if(Level1Mode == OperMode && OperatingPanel->Enabled && OperatingPanel->Visible && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10804  { //use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
10805  if(!Shift.Contains(ssCtrl))
10806  {
10807  if(OperateButton->Visible && OperateButton->Enabled)
10808  {
10809  if(Level2OperMode == Operating && (Key == 'P' || Key == 'p'))
10810  {
10811  OperateButton->Click();
10812  }
10813  else if((Level2OperMode == Paused || Level2OperMode == PreStart) && (Key == 'R' || Key == 'r'))
10814  {
10815  OperateButton->Click();
10816  }
10817  }
10818  if(PresetAutoSigRoutesButton->Visible && PresetAutoSigRoutesButton->Enabled && (Key == 'A' || Key == 'a'))
10819  {
10820  PresetAutoSigRoutesButton->Click();
10821  }
10822  if(PerformanceLogButton->Visible && PerformanceLogButton->Enabled && (Key == 'L' || Key == 'l'))
10823  {
10824  PerformanceLogButton->Click();
10825  }
10826  if(CallingOnButton->Visible && CallingOnButton->Enabled && (Key == 'O' || Key == 'o'))
10827  {
10828  CallingOnButton->Click();
10829  }
10830  if(OperatorActionButton->Visible && OperatorActionButton->Enabled && (Key == 'D' || Key == 'd'))
10831  {
10832  OperatorActionButton->Click();
10833  }
10834  if(RouteCancelButton->Visible && RouteCancelButton->Enabled && (Key == 'C' || Key == 'c'))
10835  {
10836  RouteCancelButton->Click();
10837  }
10838  if(TTClockAdjButton->Visible && TTClockAdjButton->Enabled && (Key == 'T' || Key == 't'))
10839  {
10840  TTClockAdjButton->Click();
10841  }
10842  if(AutoSigsButton->Visible && AutoSigsButton->Enabled && Key == '1') //route buttons - autosigs
10843  {
10844  AutoSigsButton->Click();
10845  }
10846  if(SigPrefConsecButton->Visible && SigPrefConsecButton->Enabled && Key == '2') //route buttons - prefdir
10847  {
10848  SigPrefConsecButton->Click();
10849  }
10850  if(SigPrefNonConsecButton->Visible && SigPrefNonConsecButton->Enabled && Key == '4') //added at v2.7.0 for prefdir & any following signal
10851  {
10852  SigPrefNonConsecButton->Click();
10853  }
10854  if(UnrestrictedButton->Visible && UnrestrictedButton->Enabled && Key == '3') //route buttons - unrestricted
10855  {
10856  UnrestrictedButton->Click();
10857  }
10858  if(ExitOperationButton->Visible && ExitOperationButton->Enabled && Key == '\x1b')
10859  {
10860  ExitOperationButton->Click();
10861  }
10862  }
10863  else //CtrlKey down
10864  {
10865  if(SaveSessionButton->Visible && SaveSessionButton->Enabled)
10866  {
10867  SaveMenuItem->ShortCut = 0; //It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
10868  if(Key == 'S' || Key == 's')//so this will never execute
10869  {
10870  SaveSessionButton->Click();
10871  }
10872  }
10873  }
10874  }
10875 
10876 //Timetable clock adjust panel
10877  if(Level1Mode == OperMode && TTClockAdjPanel->Enabled && TTClockAdjPanel->Visible && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
10878  { //use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
10879  if(Shift.Contains(ssShift))
10880  {
10881  if(TTClockExitButton->Visible && TTClockExitButton->Enabled && (Key == 'A' || Key == 'a'))
10882  {
10883  TTClockExitButton->Click();
10884  }
10885  if(TTClockResetButton->Visible && TTClockResetButton->Enabled && (Key == 'R' || Key == 'r'))
10886  {
10887  TTClockResetButton->Click();
10888  }
10889  }
10890  }
10891 
10892 //Track build panel
10893  if((Level1Mode == TrackMode) && TrackBuildPanel->Visible && TrackBuildPanel->Enabled)
10894  {
10895  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
10896  {
10897  if(AddTrackButton->Visible && AddTrackButton->Enabled && (Key == 'A' || Key == 'a')) //add/remove track elements
10898  {
10899  AddTrackButton->Click();
10900  }
10901  if(SigAspectButton->Visible && SigAspectButton->Enabled && (Key == 'S' || Key == 's')) //cycle through signal aspects
10902  {
10903  SigAspectButton->Click();
10904  }
10905  if(TrackOKButton->Visible && TrackOKButton->Enabled && (Key == 'L' || Key == 'l')) //link track
10906  {
10907  TrackOKButton->Click();
10908  }
10909  if(FontButton->Visible && FontButton->Enabled && (Key == 'F' || Key == 'f')) //change font
10910  {
10911  FontButton->Click();
10912  }
10913  if(LocationNameButton->Visible && LocationNameButton->Enabled && (Key == 'N' || Key == 'n')) //name locations
10914  {
10915  LocationNameButton->Click();
10916  }
10917  if(SetLengthsButton->Visible && SetLengthsButton->Enabled && (Key == 'D' || Key == 'd')) //set distances/speeds
10918  {
10919  SetLengthsButton->Click();
10920  }
10921  if(AddTextButton->Visible && AddTextButton->Enabled && (Key == 'T' || Key == 't')) //add text
10922  {
10923  AddTextButton->Click();
10924  }
10925  if(ScreenGridButton->Visible && ScreenGridButton->Enabled && (Key == 'G' || Key == 'g')) //toggle grid
10926  {
10927  ScreenGridButton->Click();
10928  }
10929  if(MoveTextOrGraphicButton->Visible && MoveTextOrGraphicButton->Enabled && (Key == 'M' || Key == 'm')) //move text or graphic
10930  {
10931  MoveTextOrGraphicButton->Click();
10932  }
10933  if(UserGraphicButton->Visible && UserGraphicButton->Enabled && (Key == 'I' || Key == 'i')) //insert image
10934  {
10935  UserGraphicButton->Click();
10936  }
10937  if(SetGapsButton->Visible && SetGapsButton->Enabled && (Key == 'J' || Key == 'j')) //join gaps
10938  {
10939  SetGapsButton->Click();
10940  }
10941  }
10942  if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10943  {
10944  if(SaveRailwayTBPButton->Visible && SaveRailwayTBPButton->Enabled) //save railway in trackbuild mode
10945  {
10946  SaveMenuItem->ShortCut = 0; //It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
10947  if(Key == 'S' || Key == 's')//so this will never execute
10948  {
10949  SaveRailwayTBPButton->Click();
10950  }
10951  }
10952  }
10953  if(!Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10954  {
10955  if((ExitTrackButton->Visible && ExitTrackButton->Enabled) && Key == '\x1b') //escape key
10956  {
10957  ExitTrackButton->Click();
10958  }
10959  }
10960  }
10961 
10962 //PrefDir panel
10963  if(Level1Mode == PrefDirMode && PrefDirPanel->Visible && PrefDirPanel->Enabled && !Shift.Contains(ssAlt))
10964  {
10965  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10966  {
10967  if((ExitPrefDirButton->Visible && ExitPrefDirButton->Enabled) && Key == '\x1b') //escape key
10968  {
10969  ExitPrefDirButton->Click();
10970  }
10971  }
10972  if(!Shift.Contains(ssShift) && Shift.Contains(ssCtrl))
10973  {
10974  if(SaveRailwayPDPButton->Visible && SaveRailwayPDPButton->Enabled)
10975  {
10976  SaveMenuItem->ShortCut = 0; //It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
10977  if(Key == 'S' || Key == 's')//so this will never execute
10978  {
10979  SaveRailwayPDPButton->Click();
10980  }
10981  }
10982  }
10983  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10984  {
10985  if(AddPrefDirButton->Visible && AddPrefDirButton->Enabled && (Key == 'A' || Key == 'a')) //add pref dir
10986  {
10987  AddPrefDirButton->Click();
10988  }
10989  if(DeleteOnePrefDirButton->Visible && DeleteOnePrefDirButton->Enabled && (Key == 'D' || Key == 'd')) //delete one pref dir
10990  {
10991  DeleteOnePrefDirButton->Click();
10992  }
10993  if(DeleteAllPrefDirButton->Visible && DeleteAllPrefDirButton->Enabled && (Key == 'C' || Key == 'c')) //delete all pref dirs
10994  {
10995  DeleteAllPrefDirButton->Click();
10996  }
10997  }
10998  }
10999 //Note that save button in BaseMode is handled by Ctrl S from the File menu
11000 
11001 //Timetable panel
11002  if(Level1Mode == TimetableMode && TimetablePanel->Visible && TimetablePanel->Enabled && !Shift.Contains(ssAlt))
11003  {
11004  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
11005  {
11006  if(ExitTTModeButton->Visible && ExitTTModeButton->Enabled && Key == '\x1b') //escape key
11007  {
11008  ExitTTModeButton->Click();
11009  }
11010  }
11011  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl)) //show/hide timetable edit panel
11012  {
11013  if(ShowHideTTButton->Visible && ShowHideTTButton->Enabled)
11014  {
11015  if(!TimetableEditPanel->Visible)
11016  {
11017  if(Key == 'S' || Key == 's')
11018  {
11019  ShowHideTTButton->Click();
11020  }
11021  }
11022  else if(Key == 'H' || Key == 'h')
11023  {
11024  ShowHideTTButton->Click();
11025  }
11026  }
11027  }
11028  }
11029 
11030 //Timetable edit panel
11031 //These just set flags. The corresponding 'Click()' function executes separately to the keypress because Windows stores the key until after any directly linked key code
11032 //is executed then selects the timetable entry that begins with the letter corresponding to the key. Without this separation the list box is left with the wrong entry
11033 //showing. See DevHistory.txt for the version after v2.4.3 for details.
11034  if(Level1Mode == TimetableMode && TimetableEditPanel->Visible && TimetableEditPanel->Enabled && !Shift.Contains(ssAlt))
11035  {
11036  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
11037  {
11038  AllEntriesTTListBoxTopPosition = AllEntriesTTListBox->TopIndex; //store value here before the Windows key press function runs (it runs after any local code)
11039  if(PreviousTTEntryButton->Enabled && (Key == 'L' || Key == 'l'))
11040  {
11041  PreviousTTEntryKeyFlag = true;
11042  }
11043  if(NextTTEntryButton->Enabled && (Key == 'N' || Key == 'n'))
11044  {
11045  NextTTEntryKeyFlag = true;
11046  }
11047  if(MoveTTEntryUpButton->Enabled && (Key == 'U' || Key == 'u'))
11048  {
11049  MoveTTEntryUpKeyFlag = true;
11050  }
11051  if(MoveTTEntryDownButton->Enabled && (Key == 'D' || Key == 'd'))
11052  {
11053  MoveTTEntryDownKeyFlag = true;
11054  }
11055  if(CopyTTEntryButton->Enabled && (Key == 'C' || Key == 'c'))
11056  {
11057  CopyTTEntryKeyFlag = true;
11058  }
11059  if(CutTTEntryButton->Enabled && (Key == 'X' || Key == 'x'))
11060  {
11061  CutTTEntryKeyFlag = true;
11062  }
11063  if(PasteTTEntryButton->Enabled && (Key == 'P' || Key == 'p'))
11064  {
11065  PasteTTEntryKeyFlag = true;
11066  }
11067  if(DeleteTTEntryButton->Enabled && (Key == 'E' || Key == 'e'))
11068  {
11069  DeleteTTEntryKeyFlag = true;
11070  }
11071 /* if(SaveTTEntryButton->Enabled && (Key == 'E' || Key == 'e')) //can't have save while editing entry as adds the letter to the entry
11072  {
11073  SaveTTEntryKeyFlag = true;
11074  }
11075  if(CancelTTActionButton->Enabled && (Key == 'K' || Key == 'k')) //can't have cancel while editing entry as adds the letter to the entry
11076  {
11077  CancelTTActionKeyFlag = true;
11078  }
11079 */
11080  if(NewTTEntryButton->Enabled && (Key == 'I' || Key == 'i'))
11081  {
11082  NewTTEntryKeyFlag = true;
11083  }
11084  if(AZOrderButton->Enabled && (Key == 'Z' || Key == 'z'))
11085  {
11086  AZOrderKeyFlag = true;
11087  }
11088 /*
11089  if(AddMinsButton->Enabled && (Key == 'M' || Key == 'm')) //can't have key here as adds the letter to the entry
11090  {
11091  AddMinsKeyFlag = true;
11092  }
11093  if(SubMinsButton->Enabled && (Key == 'B' || Key == 'b')) //can't have key here as adds the letter to the entry
11094  {
11095  SubMinsKeyFlag = true;
11096  }
11097 */
11098  if(TTServiceSyntaxCheckButton->Enabled && (Key == 'Q' || Key == 'q'))
11099  {
11101  }
11102  if(ValidateTimetableButton->Enabled && (Key == 'V' || Key == 'v'))
11103  {
11104  ValidateTimetableKeyFlag = true;
11105  }
11106  if(SaveTTButton->Enabled && (Key == 'T' || Key == 't'))
11107  {
11108  SaveTTKeyFlag = true;
11109  }
11110  if(SaveTTAsButton->Enabled && (Key == 'A' || Key == 'a'))
11111  {
11112  SaveTTAsKeyFlag = true;
11113  }
11114  if(RestoreTTButton->Enabled && (Key == 'R' || Key == 'r'))
11115  {
11116  RestoreTTKeyFlag = true;
11117  }
11118  if(ExportTTButton->Enabled && (Key == 'O' || Key == 'o'))
11119  {
11120  ExportTTKeyFlag = true;
11121  }
11122  if(ConflictAnalysisButton->Enabled && (Key == 'F' || Key == 'f'))
11123  {
11124  ConflictAnalysisKeyFlag = true;
11125  }
11126  }
11127  }
11128 
11129 
11130 //Information menu
11131  if(FloatingInfoMenu->Enabled && !Shift.Contains(ssAlt) && Shift.Contains(ssCtrl) && Shift.Contains(ssShift))
11132  {
11133  if(Key == 'I' || Key == 'i') //toggle track info
11134  {
11135  TrackInfoOnOffMenuItem->Click();
11136  }
11137  else if(TrainInfoMenuItem->Enabled)
11138  {
11139  if(Key == 'S' || Key == 's') //toggle train status info
11140  {
11142  }
11143  else if(Key == 'T' || Key == 't') //toggle train timetable info
11144  {
11145  TrainTTInfoOnOffMenuItem->Click();
11146  }
11147 
11148  }
11149  }
11150 //end of 2.4.2 addition
11151 
11152  }
11153  catch(const Exception &e)
11154  {
11155  ErrorLog(167, e.Message);
11156  }
11157 }
11158 
11159 // ---------------------------------------------------------------------------
11160 
11161 void __fastcall TInterface::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11162 {
11163  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
11164  LastNonCtrlOrShiftKeyDown = -1; //reset value to no key down
11165  CtrlKey = false;
11166  ShiftKey = false;
11167  SaveMenuItem->ShortCut = 16467; //restore Ctrl S for save menu in case set to 0 in FormKeyDown
11168 }
11169 
11170 // ---------------------------------------------------------------------------
11171 
11172 void __fastcall TInterface::OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11173 {
11174  if((Button == mbRight) && Level2OperMode == Operating)
11175  {
11176  OutputLog1->Caption = "";
11177  }
11178 }
11179 
11180 // ---------------------------------------------------------------------------
11181 
11182 void __fastcall TInterface::OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11183 {
11184  if((Button == mbRight) && Level2OperMode == Operating)
11185  {
11186  OutputLog2->Caption = "";
11187  }
11188 }
11189 // ---------------------------------------------------------------------------
11190 
11191 void __fastcall TInterface::OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11192 {
11193  if((Button == mbRight) && Level2OperMode == Operating)
11194  {
11195  OutputLog3->Caption = "";
11196  }
11197 }
11198 
11199 // ---------------------------------------------------------------------------
11200 
11201 void __fastcall TInterface::OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11202 {
11203  if((Button == mbRight) && Level2OperMode == Operating)
11204  {
11205  OutputLog4->Caption = "";
11206  }
11207 }
11208 
11209 // ---------------------------------------------------------------------------
11210 
11211 void __fastcall TInterface::OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11212 {
11213  if((Button == mbRight) && Level2OperMode == Operating)
11214  {
11215  OutputLog5->Caption = "";
11216  }
11217 }
11218 // ---------------------------------------------------------------------------
11219 
11220 void __fastcall TInterface::OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11221 {
11222  if((Button == mbRight) && Level2OperMode == Operating)
11223  {
11224  OutputLog6->Caption = "";
11225  }
11226 }
11227 
11228 // ---------------------------------------------------------------------------
11229 
11230 void __fastcall TInterface::OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11231 {
11232  if((Button == mbRight) && Level2OperMode == Operating)
11233  {
11234  OutputLog7->Caption = "";
11235  }
11236 }
11237 
11238 // ---------------------------------------------------------------------------
11239 
11240 void __fastcall TInterface::OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11241 {
11242  if((Button == mbRight) && Level2OperMode == Operating)
11243  {
11244  OutputLog8->Caption = "";
11245  }
11246 }
11247 
11248 // ---------------------------------------------------------------------------
11249 
11250 void __fastcall TInterface::OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11251 {
11252  if((Button == mbRight) && Level2OperMode == Operating)
11253  {
11254  OutputLog9->Caption = "";
11255  }
11256 }
11257 
11258 // ---------------------------------------------------------------------------
11259 
11260 void __fastcall TInterface::OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
11261 {
11262  if((Button == mbRight) && Level2OperMode == Operating)
11263  {
11264  OutputLog10->Caption = "";
11265  }
11266 }
11267 
11268 // ---------------------------------------------------------------------------
11269 
11270 void __fastcall TInterface::AboutMenuItemClick(TObject *Sender)
11271 {
11272  try
11273  {
11274  if((Level1Mode == OperMode) && (Level2OperMode != PreStart))
11275  // if PreStart leave as is [Modified at v1.2.0 - formerly just 'if((Level1Mode == OperMode)']
11276  {
11278  SetLevel2OperMode(3);
11279  MasterClock->Enabled = false;
11280  }
11281  AboutForm->ShowModal();
11282  }
11283  catch(const Exception &e)
11284  {
11285  ErrorLog(168, e.Message);
11286  }
11287 }
11288 
11289 // ---------------------------------------------------------------------------
11290 
11291 void __fastcall TInterface::OpenHelpMenuItemClick(TObject *Sender)
11292 {
11293  try
11294  {
11295  // Helpfile allocated during construction of Interface
11296  Application->HelpKeyword(u"Introduction"); // added at v2.0.0 for .chm help file
11297  }
11298  catch(const Exception &e)
11299  {
11300  ErrorLog(175, e.Message);
11301  }
11302 }
11303 
11304 // ---------------------------------------------------------------------------
11305 
11306 void __fastcall TInterface::RailwayWebSiteMenuItemClick(TObject *Sender)
11307 {
11308  const UnicodeString Link = "http://www.railwayoperationsimulator.com";
11309  ::ShellExecute(Handle, NULL, (Link).c_str(), NULL, NULL, SW_SHOWNORMAL);
11310 }
11311 
11312 // ---------------------------------------------------------------------------
11313 
11314 void __fastcall TInterface::BlackBgndMenuItemClick(TObject *Sender)
11315 {
11316  try
11317  {
11318  TrainController->LogEvent("BlackBgndMenuItemClick");
11319  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlackBgndMenuItemClick");
11320  TColor OldTransparentColour = Utilities->clTransparent;
11321  Utilities->clTransparent = TColor(0);
11322  SelectBitmap->TransparentColor = Utilities->clTransparent;
11325 
11326  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
11327  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
11328  Level1Mode = BaseMode;
11329  SetLevel1Mode(128);
11330  Utilities->CallLogPop(1797);
11331  }
11332  catch(const Exception &e)
11333  {
11334  ErrorLog(170, e.Message);
11335  }
11336 }
11337 
11338 // ---------------------------------------------------------------------------
11339 
11340 void __fastcall TInterface::WhiteBgndMenuItemClick(TObject *Sender)
11341 {
11342  try
11343  {
11344  TrainController->LogEvent("WhiteBgndMenuItemClick");
11345  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",WhiteBgndMenuItemClick");
11346  TColor OldTransparentColour = Utilities->clTransparent;
11347  Utilities->clTransparent = TColor(0xFFFFFF);
11348  SelectBitmap->TransparentColor = Utilities->clTransparent;
11351 
11352  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
11353  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
11354  Level1Mode = BaseMode;
11355  SetLevel1Mode(129);
11356  Utilities->CallLogPop(1798);
11357  }
11358  catch(const Exception &e)
11359  {
11360  ErrorLog(171, e.Message);
11361  }
11362 }
11363 
11364 // ---------------------------------------------------------------------------
11365 
11366 void __fastcall TInterface::BlueBgndMenuItemClick(TObject *Sender)
11367 {
11368  try
11369  {
11370  TrainController->LogEvent("BlueBgndMenuItemClick");
11371  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlueBgndMenuItemClick");
11372  TColor OldTransparentColour = Utilities->clTransparent;
11373  Utilities->clTransparent = TColor(0x330000);
11374  SelectBitmap->TransparentColor = Utilities->clTransparent;
11377 
11378  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
11379  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
11380  Level1Mode = BaseMode;
11381  SetLevel1Mode(130);
11382  Utilities->CallLogPop(1799);
11383  }
11384  catch(const Exception &e)
11385  {
11386  ErrorLog(172, e.Message);
11387  }
11388 }
11389 
11390 // ---------------------------------------------------------------------------
11391 
11392 void __fastcall TInterface::SpeedToggleButtonClick(TObject *Sender)
11393 {
11394  if(SpeedTopLabel->Caption == "mph")
11395  {
11396  SpeedTopLabel->Caption = "km/h";
11397  SpeedBottomLabel->Caption = "mph";
11398  }
11399  else
11400  {
11401  SpeedTopLabel->Caption = "mph";
11402  SpeedBottomLabel->Caption = "km/h";
11403  }
11404  // swap values to match toggle state
11405  UnicodeString SavedTopValue = SpeedEditBox->Text;
11406  UnicodeString SavedBottomValue = SpeedVariableLabel->Caption;
11407 
11408  SpeedEditBox->Text = SavedBottomValue;
11409  SpeedVariableLabel->Caption = SavedTopValue;
11410 }
11411 // ---------------------------------------------------------------------------
11412 
11413 void __fastcall TInterface::SpeedToggleButton2Click(TObject *Sender)
11414 {
11415  if(SpeedTopLabel2->Caption == "mph")
11416  {
11417  SpeedTopLabel2->Caption = "km/h";
11418  SpeedBottomLabel2->Caption = "mph";
11419  }
11420  else
11421  {
11422  SpeedTopLabel2->Caption = "mph";
11423  SpeedBottomLabel2->Caption = "km/h";
11424  }
11425  // swap values to match toggle state
11426  UnicodeString SavedTopValue = SpeedEditBox2->Text;
11427  UnicodeString SavedBottomValue = SpeedVariableLabel2->Caption;
11428 
11429  SpeedEditBox2->Text = SavedBottomValue;
11430  SpeedVariableLabel2->Caption = SavedTopValue;
11431 }
11432 // ---------------------------------------------------------------------------
11433 
11434 void __fastcall TInterface::SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11435 {
11436  try
11437  {
11438  TrainController->LogEvent("SpeedEditBoxKeyUp," + AnsiString(Key));
11439  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBoxKeyUp," + AnsiString(Key));
11440  bool ErrorFlag = false, TooBigFlag = false;
11441  if(SpeedEditBox->Text.Length() > 0)
11442  {
11443  if(SpeedEditBox->Text.Length() > 5)
11444  {
11445  TooBigFlag = true;
11446  }
11447  for(int x = 1; x <= SpeedEditBox->Text.Length(); x++)
11448  {
11449  if((SpeedEditBox->Text[x] < '0') || (SpeedEditBox->Text[x] > '9'))
11450  {
11451  SpeedVariableLabel->Caption = "Entry error";
11452  ErrorFlag = true;
11453  break;
11454  }
11455  if(TooBigFlag)
11456  {
11457  SpeedVariableLabel->Caption = "Too big";
11458  break;
11459  }
11460  }
11461  if(!ErrorFlag && !TooBigFlag)
11462  {
11463 /*
11464  1 mph = 1.609344 km/h
11465  1 km/h = 0.621371 mph
11466 */
11467  if(SpeedTopLabel->Caption == "mph")
11468  {
11469  // do mph-to-km/h conversion
11470  int MPH = SpeedEditBox->Text.ToInt();
11471  int KPH = (MPH * 1.609344) + 0.5;
11472  SpeedVariableLabel->Caption = UnicodeString(KPH);
11473  }
11474  else
11475  {
11476  // do km/h-to-mph conversion
11477  int KPH = SpeedEditBox->Text.ToInt();
11478  int MPH = (KPH * 0.621371) + 0.5;
11479  SpeedVariableLabel->Caption = UnicodeString(MPH);
11480  }
11481  }
11482  }
11483  else
11484  {
11485  SpeedVariableLabel->Caption = "";
11486  }
11487  Utilities->CallLogPop(1865);
11488  }
11489  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11490  {
11491  SpeedVariableLabel->Caption = "Entry error";
11492  }
11493  catch(const Exception &e)
11494  {
11495  ErrorLog(176, e.Message);
11496  }
11497 }
11498 
11499 // ---------------------------------------------------------------------------
11500 
11501 void __fastcall TInterface::PowerToggleButtonClick(TObject *Sender)
11502 {
11503  if(PowerTopLabel->Caption == "HP")
11504  {
11505  PowerTopLabel->Caption = "kW";
11506  PowerBottomLabel->Caption = "HP";
11507  }
11508  else
11509  {
11510  PowerTopLabel->Caption = "HP";
11511  PowerBottomLabel->Caption = "kW";
11512  }
11513  // swap values to match toggle state
11514  UnicodeString SavedTopValue = PowerEditBox->Text;
11515  UnicodeString SavedBottomValue = PowerVariableLabel->Caption;
11516 
11517  PowerEditBox->Text = SavedBottomValue;
11518  PowerVariableLabel->Caption = SavedTopValue;
11519 }
11520 // ---------------------------------------------------------------------------
11521 
11522 void __fastcall TInterface::PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11523 {
11524  try
11525  {
11526  TrainController->LogEvent("PowerEditBoxKeyUp," + AnsiString(Key));
11527  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PowerEditBoxKeyUp," + AnsiString(Key));
11528  bool ErrorFlag = false, TooBigFlag = false;
11529  if(PowerEditBox->Text.Length() > 0)
11530  {
11531  if(PowerEditBox->Text.Length() > 8)
11532  {
11533  TooBigFlag = true;
11534  }
11535  for(int x = 1; x <= PowerEditBox->Text.Length(); x++)
11536  {
11537  if((PowerEditBox->Text[x] < '0') || (PowerEditBox->Text[x] > '9'))
11538  {
11539  PowerVariableLabel->Caption = "Entry error";
11540  ErrorFlag = true;
11541  break;
11542  }
11543  if(TooBigFlag)
11544  {
11545  PowerVariableLabel->Caption = "Too big";
11546  break;
11547  }
11548  }
11549  if(!ErrorFlag && !TooBigFlag)
11550  {
11551 /*
11552  1 kW = 1.340482574 HP
11553  1 HP = 0.745699872 kW
11554 */
11555  if(PowerTopLabel->Caption == "HP")
11556  {
11557  // do HP-to-kW conv
11558  int HP = PowerEditBox->Text.ToInt();
11559  int KW = (HP * 0.745699872) + 0.5;
11560  PowerVariableLabel->Caption = UnicodeString(KW);
11561  }
11562  else
11563  {
11564  // do kW-to-HP conv
11565  int KW = PowerEditBox->Text.ToInt();
11566  int HP = (KW * 1.340482574) + 0.5;
11567  PowerVariableLabel->Caption = UnicodeString(HP);
11568  }
11569  }
11570  }
11571  else
11572  {
11573  PowerVariableLabel->Caption = "";
11574  }
11575  Utilities->CallLogPop(1868);
11576  }
11577  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11578  {
11579  PowerVariableLabel->Caption = "Entry error";
11580  }
11581  catch(const Exception &e)
11582  {
11583  ErrorLog(179, e.Message);
11584  }
11585 }
11586 // ---------------------------------------------------------------------------
11587 
11588 void __fastcall TInterface::SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11589 {
11590  try
11591  {
11592  TrainController->LogEvent("SpeedEditBox2KeyUp," + AnsiString(Key));
11593  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBox2KeyUp," + AnsiString(Key));
11594  bool ErrorFlag = false, TooBigFlag = false;
11595  if(SpeedEditBox2->Text.Length() > 0)
11596  {
11597  if(SpeedEditBox2->Text.Length() > 5)
11598  {
11599  TooBigFlag = true;
11600  }
11601  for(int x = 1; x <= SpeedEditBox2->Text.Length(); x++)
11602  {
11603  if((SpeedEditBox2->Text[x] < '0') || (SpeedEditBox2->Text[x] > '9'))
11604  {
11605  SpeedVariableLabel2->Caption = "Entry error";
11606  ErrorFlag = true;
11607  break;
11608  }
11609  if(TooBigFlag)
11610  {
11611  SpeedVariableLabel2->Caption = "Too big";
11612  break;
11613  }
11614  }
11615  if(!ErrorFlag && !TooBigFlag)
11616  {
11617 /*
11618  1 mph = 1.609344 km/h
11619  1 km/h = 0.621371 mph
11620 */
11621  if(SpeedTopLabel2->Caption == "mph")
11622  {
11623  // do mph-to-km/h conversion
11624  int MPH = SpeedEditBox2->Text.ToInt();
11625  int KPH = (MPH * 1.609344) + 0.5;
11626  SpeedVariableLabel2->Caption = AnsiString(KPH);
11627  }
11628  else
11629  {
11630  // do km/h-to-mph conversion
11631  int KPH = SpeedEditBox2->Text.ToInt();
11632  int MPH = (KPH * 0.621371) + 0.5;
11633  SpeedVariableLabel2->Caption = AnsiString(MPH);
11634  }
11635  }
11636  }
11637  else
11638  {
11639  SpeedVariableLabel2->Caption = "";
11640  }
11641  Utilities->CallLogPop(1866);
11642  }
11643  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11644  {
11645  SpeedVariableLabel2->Caption = "Entry error";
11646  }
11647  catch(const Exception &e)
11648  {
11649  ErrorLog(177, e.Message);
11650  }
11651 }
11652 
11653 // ---------------------------------------------------------------------------
11654 
11655 void __fastcall TInterface::LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11656 {
11657  try
11658  {
11659  TrainController->LogEvent("LengthEditKeyUp," + AnsiString(Key));
11660  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthEditKeyUp," + AnsiString(Key));
11661  bool ErrorFlag = false, TooLongFlag = false;
11662  if((MileEdit->Text.Length() > 0) && (MileEdit->Text.Length() < 6))
11663  {
11664  for(int x = 1; x <= MileEdit->Text.Length(); x++)
11665  {
11666  if((MileEdit->Text[x] < '0') || (MileEdit->Text[x] > '9'))
11667  {
11668  MetreVariableLabel->Caption = "Entry error";
11669  ErrorFlag = true;
11670  break;
11671  }
11672  }
11673  }
11674  if((ChainEdit->Text.Length() > 0) && (ChainEdit->Text.Length() < 6))
11675  {
11676  for(int x = 1; x <= ChainEdit->Text.Length(); x++)
11677  {
11678  if((ChainEdit->Text[x] < '0') || (ChainEdit->Text[x] > '9'))
11679  {
11680  MetreVariableLabel->Caption = "Entry error";
11681  ErrorFlag = true;
11682  break;
11683  }
11684  }
11685  }
11686  if((YardEdit->Text.Length() > 0) && (YardEdit->Text.Length() < 6))
11687  {
11688  for(int x = 1; x <= YardEdit->Text.Length(); x++)
11689  {
11690  if((YardEdit->Text[x] < '0') || (YardEdit->Text[x] > '9'))
11691  {
11692  MetreVariableLabel->Caption = "Entry error";
11693  ErrorFlag = true;
11694  break;
11695  }
11696  }
11697  }
11698  if((MileEdit->Text.Length() > 5) || (ChainEdit->Text.Length() > 5) || (YardEdit->Text.Length() > 5))
11699  {
11700  TooLongFlag = true;
11701  MetreVariableLabel->Caption = "Too big";
11702  }
11703  if(!ErrorFlag && !TooLongFlag)
11704  {
11705  int Miles = 0, Chains = 0, Yards = 0, Metres = 0;
11706  if(MileEdit->Text.Length() > 0)
11707  {
11708  Miles = MileEdit->Text.ToInt();
11709  }
11710  if(ChainEdit->Text.Length() > 0)
11711  {
11712  Chains = ChainEdit->Text.ToInt();
11713  }
11714  if(YardEdit->Text.Length() > 0)
11715  {
11716  Yards = YardEdit->Text.ToInt();
11717  }
11718  Metres = int((Miles * 1609.344) + (Chains * 20.1168) + (Yards * 0.9144) + 0.5);
11719  MetreVariableLabel->Caption = AnsiString(Metres);
11720  }
11721  if((MileEdit->Text.Length() == 0) && (ChainEdit->Text.Length() == 0) && (YardEdit->Text.Length() == 0))
11722  {
11723  MetreVariableLabel->Caption = "";
11724  }
11725  Utilities->CallLogPop(1867);
11726  }
11727  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11728  {
11729  MetreVariableLabel->Caption = "Entry error";
11730  }
11731  catch(const Exception &e)
11732  {
11733  ErrorLog(178, e.Message);
11734  }
11735 }
11736 
11737 // ---------------------------------------------------------------------------
11738 
11739 void __fastcall TInterface::TTClockAdjButtonClick(TObject *Sender)
11740 {
11741  try
11742  {
11743  TrainController->LogEvent("TTClockAdjButtonClick");
11744  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjButtonClick");
11745 // Utilities->Clock2Stopped = true; // to keep panel buttons disabled, restarted on exit
11746  Display->HideWarningLog(0); //because this panel overwrites it
11747  TTClockAdjPanel->Visible = true;
11748  TTClockAdjButton->Enabled = false;
11749 /*
11750  OperatingPanelLabel->Caption = "Disabled"; all these now dealt with in ClockTimer2
11751  OperatingPanel->Enabled = false;
11752  ZoomButton->Enabled = false;
11753  HomeButton->Enabled = false;
11754  NewHomeButton->Enabled = false;
11755  ScreenLeftButton->Enabled = false;
11756  ScreenRightButton->Enabled = false;
11757  ScreenUpButton->Enabled = false;
11758  ScreenDownButton->Enabled = false;
11759 */
11760  Utilities->CallLogPop(1875);
11761  }
11762  catch(const Exception &e)
11763  {
11764  ErrorLog(181, e.Message);
11765  }
11766 }
11767 
11768 // ---------------------------------------------------------------------------
11769 
11770 void __fastcall TInterface::TTClockExitButtonClick(TObject *Sender)
11771 {
11772  try
11773  {
11774  TrainController->LogEvent("TTClockExitButtonClick");
11775  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockExitButtonClick");
11776  TTClockAdjPanel->Visible = false;
11777  TTClockAdjButton->Enabled = true;
11778 /* these dealt with in ClockTimer2
11779  ZoomButton->Enabled = true;
11780  HomeButton->Enabled = true;
11781  NewHomeButton->Enabled = true;
11782  ScreenLeftButton->Enabled = true;
11783  ScreenRightButton->Enabled = true;
11784  ScreenUpButton->Enabled = true;
11785  ScreenDownButton->Enabled = true;
11786  OperatingPanel->Enabled = true;
11787  OperatingPanelLabel->Caption = "Operation";
11788 */
11789  Display->ShowWarningLog(0);
11790  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
11791  if((TTClockSpeed != PauseEntryTTClockSpeed) || (TTClockTimeChange > 0.000347))
11792  // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
11794  {
11795  TTClockAdjustWarningPanel->Top = MainScreen->Top + ((MainScreen->Height - TTClockAdjustWarningPanel->Height)/2);
11796  TTClockAdjustWarningPanel->Left = MainScreen->Left + ((MainScreen->Width - TTClockAdjustWarningPanel->Width)/2);
11797  TTClockAdjustWarningLabel->Caption =
11798  "Changes have been made to the timetable clock - you may wish to save a session before resuming operation.\n\nTo cancel all changes re-click the 'Adjust the timetable clock' button then click the reset button BEFORE resuming operation.";
11799  TTClockAdjustWarningPanel->Visible = true;
11800  }
11801 // Utilities->Clock2Stopped = false; // as above
11802  LastNonCtrlOrShiftKeyDown = -1; //to restore the ability to reselect T after adj panel hidden (FormKeyUp doesn't work because the Interface form doesn't have focus)
11803  Utilities->CallLogPop(1876);
11804  }
11805  catch(const Exception &e)
11806  {
11807  ErrorLog(182, e.Message);
11808  }
11809 }
11810 // ---------------------------------------------------------------------------
11811 
11812 void __fastcall TInterface::TTClockx2ButtonClick(TObject *Sender)
11813 {
11814  try
11815  {
11816  TrainController->LogEvent("TTClockx2ButtonClick");
11817  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx2ButtonClick");
11818  TTClockSpeed = 2;
11819  TTClockSpeedLabel->Caption = "x2";
11821  Utilities->CallLogPop(1878);
11822  }
11823  catch(const Exception &e)
11824  {
11825  ErrorLog(184, e.Message);
11826  }
11827 }
11828 
11829 // ---------------------------------------------------------------------------
11830 
11831 void __fastcall TInterface::TTClockx4ButtonClick(TObject *Sender)
11832 {
11833  try
11834  {
11835  TrainController->LogEvent("TTClockx4ButtonClick");
11836  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx4ButtonClick");
11837  TTClockSpeed = 4;
11838  TTClockSpeedLabel->Caption = "x4";
11840  Utilities->CallLogPop(1883);
11841  }
11842  catch(const Exception &e)
11843  {
11844  ErrorLog(189, e.Message);
11845  }
11846 }
11847 
11848 // ---------------------------------------------------------------------------
11849 
11850 void __fastcall TInterface::TTClockx8ButtonClick(TObject *Sender)
11851 {
11852  try
11853  {
11854  TrainController->LogEvent("TTClockx8ButtonClick");
11855  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx8ButtonClick");
11856  TTClockSpeed = 8;
11857  TTClockSpeedLabel->Caption = "x8";
11859  Utilities->CallLogPop(1884);
11860  }
11861  catch(const Exception &e)
11862  {
11863  ErrorLog(190, e.Message);
11864  }
11865 }
11866 
11867 // ---------------------------------------------------------------------------
11868 
11869 void __fastcall TInterface::TTClockx16ButtonClick(TObject *Sender)
11870 {
11871  try
11872  {
11873  TrainController->LogEvent("TTClockx16ButtonClick");
11874  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx16ButtonClick");
11875  TTClockSpeed = 16;
11876  TTClockSpeedLabel->Caption = "x16";
11878  Utilities->CallLogPop(1885);
11879  }
11880  catch(const Exception &e)
11881  {
11882  ErrorLog(191, e.Message);
11883  }
11884 }
11885 
11886 // ---------------------------------------------------------------------------
11887 
11888 void __fastcall TInterface::TTClockx1ButtonClick(TObject *Sender)
11889 {
11890  try
11891  {
11892  TrainController->LogEvent("TTClockx1ButtonClick");
11893  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx1ButtonClick");
11894  TTClockSpeed = 1;
11895  TTClockSpeedLabel->Caption = "x1";
11897  Utilities->CallLogPop(1886);
11898  }
11899  catch(const Exception &e)
11900  {
11901  ErrorLog(192, e.Message);
11902  }
11903 }
11904 
11905 // ---------------------------------------------------------------------------
11906 
11907 void __fastcall TInterface::TTClockxHalfButtonClick(TObject *Sender)
11908 {
11909  try
11910  {
11911  TrainController->LogEvent("TTClockxHalfButtonClick");
11912  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxHalfButtonClick");
11913  TTClockSpeed = 0.5;
11914  TTClockSpeedLabel->Caption = "x1/2";
11916  Utilities->CallLogPop(1887);
11917  }
11918  catch(const Exception &e)
11919  {
11920  ErrorLog(193, e.Message);
11921  }
11922 }
11923 
11924 // ---------------------------------------------------------------------------
11925 
11926 void __fastcall TInterface::TTClockxQuarterButtonClick(TObject *Sender)
11927 {
11928  try
11929  {
11930  TrainController->LogEvent("TTClockxQuarterButtonClick");
11931  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxQuarterButtonClick");
11932  TTClockSpeed = 0.25;
11933  TTClockSpeedLabel->Caption = "x1/4";
11935  Utilities->CallLogPop(1888);
11936  }
11937  catch(const Exception &e)
11938  {
11939  ErrorLog(194, e.Message);
11940  }
11941 }
11942 
11943 // ---------------------------------------------------------------------------
11944 
11945 void __fastcall TInterface::TTClockxEighthButtonClick(TObject *Sender)
11946 { // added for v2.3.0 for very big railways
11947  try
11948  {
11949  TrainController->LogEvent("TTClockxEighthButtonClick");
11950  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxEighthButtonClick");
11951  TTClockSpeed = 0.125;
11952  TTClockSpeedLabel->Caption = "x1/8";
11954  Utilities->CallLogPop(2099);
11955  }
11956  catch(const Exception &e)
11957  {
11958  ErrorLog(203, e.Message);
11959  }
11960 }
11961 // ---------------------------------------------------------------------------
11962 
11963 void __fastcall TInterface::TTClockxSixteenthButtonClick(TObject *Sender)
11964 { // added for v2.3.0 for very big railways
11965  try
11966  {
11967  TrainController->LogEvent("TTClockxSixteenthButtonClick");
11968  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxSixteenthButtonClick");
11969  TTClockSpeed = 0.0625;
11970  TTClockSpeedLabel->Caption = "x1/16";
11972  Utilities->CallLogPop(2100);
11973  }
11974  catch(const Exception &e)
11975  {
11976  ErrorLog(204, e.Message);
11977  }
11978 }
11979 
11980 // ---------------------------------------------------------------------------
11981 
11982 void __fastcall TInterface::TTClockAdd1hButtonClick(TObject *Sender)
11983 {
11984  try
11985  {
11986  TrainController->LogEvent("TTClockAdd1hButtonClick");
11987  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1hButtonClick");
11988  double TTClockIncrement = 1.0 / 24;
11989  TrainController->RestartTime += TDateTime(TTClockIncrement);
11992  Utilities->CallLogPop(1879);
11993  }
11994  catch(const Exception &e)
11995  {
11996  ErrorLog(185, e.Message);
11997  }
11998 }
11999 
12000 // ---------------------------------------------------------------------------
12001 
12002 void __fastcall TInterface::TTClockAdd10mButtonClick(TObject *Sender)
12003 {
12004  try
12005  {
12006  TrainController->LogEvent("TTClockAdd10mButtonClick");
12007  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd10mButtonClick");
12008  double TTClockIncrement = 1.0 / 144;
12009  TrainController->RestartTime += TDateTime(TTClockIncrement);
12012  Utilities->CallLogPop(1881);
12013  }
12014  catch(const Exception &e)
12015  {
12016  ErrorLog(187, e.Message);
12017  }
12018 }
12019 
12020 // ---------------------------------------------------------------------------
12021 
12022 void __fastcall TInterface::TTClockAdd1mButtonClick(TObject *Sender)
12023 {
12024  try
12025  {
12026  TrainController->LogEvent("TTClockAdd1mButtonClick");
12027  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1mButtonClick");
12028  double TTClockIncrement = 1.0 / 1440;
12029  TrainController->RestartTime += TDateTime(TTClockIncrement);
12032  Utilities->CallLogPop(1882);
12033  }
12034  catch(const Exception &e)
12035  {
12036  ErrorLog(188, e.Message);
12037  }
12038 }
12039 
12040 // ---------------------------------------------------------------------------
12041 
12042 void __fastcall TInterface::TTClockResetButtonClick(TObject *Sender)
12043 {
12044  try
12045  {
12046  TrainController->LogEvent("TTClockResetButtonClick");
12047  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockResetButtonClick");
12052  if(TTClockSpeed == 2)
12053  TTClockSpeedLabel->Caption = "x2";
12054  else if(TTClockSpeed == 4)
12055  TTClockSpeedLabel->Caption = "x4";
12056  else if(TTClockSpeed == 8)
12057  TTClockSpeedLabel->Caption = "x8";
12058  else if(TTClockSpeed == 16)
12059  TTClockSpeedLabel->Caption = "x16";
12060  else if(TTClockSpeed == 0.5)
12061  TTClockSpeedLabel->Caption = "x1/2";
12062  else if(TTClockSpeed == 0.25)
12063  TTClockSpeedLabel->Caption = "x1/4";
12064  else if(TTClockSpeed == 0.125)
12065  TTClockSpeedLabel->Caption = "x1/8";
12066  else if(TTClockSpeed == 0.0625)
12067  TTClockSpeedLabel->Caption = "x1/16";
12068  else
12069  {
12070  TTClockSpeed = 1;
12071  TTClockSpeedLabel->Caption = "x1";
12072  }
12073  Utilities->CallLogPop(1880);
12074  }
12075  catch(const Exception &e)
12076  {
12077  ErrorLog(186, e.Message);
12078  }
12079 }
12080 
12081 // ---------------------------------------------------------------------------
12082 
12083 void __fastcall TInterface::PresetAutoSigRoutesButtonClick(TObject *Sender)
12084 {
12085  try
12086  {
12087  TrainController->LogEvent("PresetAutoSigRoutesButtonClick");
12088  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PresetAutoSigRoutesButtonClick");
12089  InfoPanel->Caption = "PRE-START: Presetting automatic signal routes";
12090  OperatingPanelLabel->Caption = "Disabled";
12091  OperatingPanel->Enabled = false; // becomes re-enabled during the call to ClockTimer2
12092  ZoomButton->Enabled = false;
12093  HomeButton->Enabled = false;
12094  NewHomeButton->Enabled = false;
12095  ScreenLeftButton->Enabled = false;
12096  ScreenRightButton->Enabled = false;
12097  ScreenUpButton->Enabled = false;
12098  ScreenDownButton->Enabled = false;
12099 
12100  Screen->Cursor = TCursor(-11); // Hourglass
12101  TPrefDirElement StartElement, EndElement;
12102  bool PointsChanged, AtLeastOneSet = false;
12103  int LastIteratorValue = 0;
12104  while(true)
12105  {
12106  if(!EveryPrefDir->GetStartAndEndPrefDirElements(0, StartElement, EndElement, LastIteratorValue))
12107  break;
12108  // rest of routine here - i.e. build the routes
12109  ConstructRoute->ClearRoute(); // in case not empty though should be
12110  AtLeastOneSet = true;
12111  if(ConstructRoute->GetPreferredRouteStartElement(1, StartElement.HLoc, StartElement.VLoc, EveryPrefDir, true)) // true for AutoSigsFlag
12112  {}
12113  if(ConstructRoute->GetNextPreferredRouteElement(1, EndElement.HLoc, EndElement.VLoc, EveryPrefDir, true, true, ConstructRoute->ReqPosRouteID,
12114  PointsChanged))
12115  {}
12117  }
12118  if(AtLeastOneSet)
12119  {
12122  }
12123  else
12124  {
12125  ShowMessage("No presettable automatic signal routes are available");
12126  }
12127  Screen->Cursor = TCursor(-2); // Arrow
12128  Utilities->CallLogPop(1994);
12129  }
12130  catch(const Exception &e)
12131  {
12132  ErrorLog(195, e.Message);
12133  }
12134 }
12135 
12136 // ---------------------------------------------------------------------------
12137 
12138 void __fastcall TInterface::FormResize(TObject *Sender) // new at v2.1.0
12139 {
12140  try
12141  {
12142  if(!SkipFormResizeEvent) // to avoid calling during startup and especially during shutdown
12143  { // else fails on shutdown because HiddenScreen & other things no longer exist
12144  int DispW = (Interface->Width - 64 - 16) / 16;
12145 // will truncate down to a multiple of 16 (64 = side panels and 16 compensates for excess width of Interface)
12146  int DispH = (Interface->Height - 192) / 16;
12147  MainScreen->Width = DispW * 16;
12148  MainScreen->Height = DispH * 16;
12149  Utilities->ScreenElementWidth = DispW;
12150  Utilities->ScreenElementHeight = DispH;
12151  HiddenScreen->Width = MainScreen->Width;
12152  HiddenScreen->Height = MainScreen->Height;
12153  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
12154  PerformancePanel->Left = MainScreen->Left;
12155  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new at v2.2.0
12156  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
12157  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
12158  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height; // new v2.2.0
12159  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width; // new v2.2.0
12160  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 32; // new v2.4.0 32 is to place it above the positional panel
12161  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
12162  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
12163  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
12164  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
12165 
12166  if(!Display->ZoomOutFlag)
12167  {
12169  }
12170  else
12171  {
12172  Display->ClearDisplay(11);
12174  }
12175  Display->Update();
12176  }
12177  }
12178  catch(const Exception &e)
12179  {
12180  ErrorLog(197, e.Message);
12181  }
12182 }
12183 
12184 // ---------------------------------------------------------------------------
12185 
12186 void __fastcall TInterface::OperatorActionButtonClick(TObject *Sender)
12187 {
12188  try
12189  {
12190  TrainController->LogEvent("OperatorActionButtonClick");
12191  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionButtonClick");
12193  {
12194  ShowOperatorActionPanel = true;
12195  OperatorActionPanel->Visible = true;
12197  OperatorActionButton->Glyph->LoadFromResourceName(0, "HideOpActionPanel");
12198  }
12199  else
12200  {
12201  ShowOperatorActionPanel = false;
12202  OperatorActionPanel->Visible = false;
12204  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
12205  }
12206  Utilities->CallLogPop(2073);
12207  }
12208  catch(const Exception &e)
12209  {
12210  ErrorLog(199, e.Message);
12211  }
12212 }
12213 
12214 // ---------------------------------------------------------------------------
12215 
12217 {
12218  try
12219  {
12220  TrainController->LogEvent("ConverttoRightHandSignalsMenuItemClick");
12221  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConverttoRightHandSignalsMenuItemClick");
12223  if(Utilities->RHSignalFlag) // RH sigs after conversion
12224  {
12225  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
12227  {
12229  }
12230  else
12231  {
12233  }
12234  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
12235  SigsOnLeftImage1->Visible = false;
12236  SigsOnLeftImage2->Visible = false;
12237  SigsOnRightImage1->Visible = true;
12238  SigsOnRightImage2->Visible = true;
12239  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
12240  if(SigFile.fail())
12241  {
12242  ShowMessage("Failed to store right hand signal setting, program will default to left hand signals when next loaded");
12243  }
12244  else
12245  {
12246  Utilities->SaveFileString(SigFile, "RHSignals");
12247  }
12248  }
12249  else // LH sigs after conversion
12250  {
12251  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
12253  {
12255  }
12256  else
12257  {
12259  }
12260  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
12261  SigsOnRightImage1->Visible = false;
12262  SigsOnRightImage2->Visible = false;
12263  SigsOnLeftImage1->Visible = true;
12264  SigsOnLeftImage2->Visible = true;
12265  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
12266  if(SigFile.fail())
12267  {
12268  // no need for message as will default to LH: ShowMessage("Failed to store left hand signal setting, program will default to left hand signals when next loaded");
12269  }
12270  else
12271  {
12272  Utilities->SaveFileString(SigFile, "LHSignals");
12273  }
12274  }
12275  Utilities->CallLogPop(2097);
12276  }
12277  catch(const Exception &e)
12278  {
12279  ErrorLog(202, e.Message);
12280  }
12281 }
12282 // ---------------------------------------------------------------------------
12283 
12284 void __fastcall TInterface::MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
12285 
12286 {
12287  try
12288  {
12289  TrainController->LogEvent("MTBFEditBoxKeyUp," + AnsiString(Key));
12290  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxKeyUp," + AnsiString(Key));
12291  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
12292  {
12293  Utilities->CallLogPop(2160);
12294  return;
12295  }
12296  bool TooBigFlag = false, BadCharsFlag = false;
12299  if(MTBFEditBox->Text.Length() > 0)
12300  {
12301  for(int x = 1; x <= MTBFEditBox->Text.Length(); x++)
12302  {
12303  if((MTBFEditBox->Text[x] < '0') || (MTBFEditBox->Text[x] > '9'))
12304  {
12305  BadCharsFlag = true;
12306  break;
12307  }
12308  }
12309  if(!BadCharsFlag)
12310  {
12311  if(StrToInt(MTBFEditBox->Text) > 10000)
12312  {
12313  TooBigFlag = true;
12314  }
12315  }
12316  if(TooBigFlag)
12317  {
12318  ShowMessage("Maximum value allowed is 10,000");
12319  MTBFEditBox->Text = "";
12322  Utilities->CallLogPop(2161);
12323  return;
12324  }
12325  if(BadCharsFlag)
12326  {
12327  ShowMessage("Value must be a whole number with no special characters");
12328  MTBFEditBox->Text = "";
12331  Utilities->CallLogPop(2162);
12332  return;
12333  }
12334  TrainController->AvHoursIntValue = StrToInt(MTBFEditBox->Text); // ok if user enters 0 as that means no failures
12336  }
12338  {
12339  MTBFEditBox->Text = "";
12341  }
12342  Utilities->CallLogPop(2163);
12343  }
12344  catch(const Exception &e)
12345  {
12346  ErrorLog(209, e.Message);
12347  }
12348 }
12349 
12350 // ---------------------------------------------------------------------------
12351 
12352 void __fastcall TInterface::MTBFEditBoxClick(TObject *Sender)
12353 {
12354  try
12355  {
12356  TrainController->LogEvent("MTBFEditBoxClick");
12357  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
12358  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
12359  {
12360  MTBFEditBox->ReadOnly = true; // it should be anyway but include here for safety
12362  "Values can only be entered or changed in Pre-Start mode\ni.e. after selecting 'Operate railway' but before clicking 'Run'");
12363  }
12364  Utilities->CallLogPop(2164);
12365  }
12366  catch(const Exception &e)
12367  {
12368  ErrorLog(210, e.Message);
12369  }
12370 }
12371 
12372 // ---------------------------------------------------------------------------
12373 
12374 void __fastcall TInterface::UserGraphicButtonClick(TObject *Sender)
12375 {
12376  try
12377  {
12378  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
12379  LengthConversionPanel->Visible = false;
12380  SpeedConversionPanel->Visible = false;
12381  DistanceKey->Visible = false;
12382  TrackElementPanel->Visible = false;
12383  SigAspectButton->Enabled = false;
12385  SetLevel2TrackMode(63);
12386  Display->Update();
12387  if((SelectedGraphicFileName != "") && (!Track->UserGraphicVector.empty())) //latter condition added at v2.6.0 because showed after ClearAll & reselect failed
12388  {
12389  UserGraphicReselectPanel->Visible = true;
12390  }
12391  else
12392  {
12393  UserGraphicReselectPanel->Visible = false;
12394  LoadUserGraphic(0);
12395  }
12396  Utilities->CallLogPop(2183);
12397  }
12398  catch(const Exception &e)
12399  {
12400  ErrorLog(212, e.Message);
12401  }
12402 }
12403 
12404 // ---------------------------------------------------------------------------
12405 
12406 void __fastcall TInterface::ReselectUserGraphicClick(TObject *Sender)
12407 {
12408  try
12409  {
12410  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectUserGraphicClick");
12411  TrainController->LogEvent("ReselectUserGraphicClick " + SelectedGraphicFileName);
12412  UserGraphicReselectPanel->Visible = false;
12413  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
12414  if(UGMIt == Track->UserGraphicMap.end())
12415  {
12416  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
12417  Utilities->CallLogPop(2196);
12418  return;
12419  }
12421  SetLevel2TrackMode(64);
12422  Utilities->CallLogPop(2184);
12423  }
12424  catch(const Exception &e)
12425  {
12426  ErrorLog(213, e.Message);
12427  }
12428 }
12429 // ---------------------------------------------------------------------------
12430 
12431 void __fastcall TInterface::SelectNewGraphicClick(TObject *Sender)
12432 {
12433  try
12434  {
12435  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectNewGraphicClick");
12436  UserGraphicReselectPanel->Visible = false;
12437  LoadUserGraphic(1);
12438  Utilities->CallLogPop(2185);
12439  }
12440  catch(const Exception &e)
12441  {
12442  ErrorLog(214, e.Message);
12443  }
12444 }
12445 
12446 // ---------------------------------------------------------------------------
12447 
12448 void __fastcall TInterface::TTClockAdjustOKButtonClick(TObject *Sender)
12449 {
12450  try
12451  {
12452  TrainController->LogEvent("TTClockAdjustOKButtonClick");
12453  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjustOKButtonClick");
12454  TTClockAdjustWarningPanel->Visible = false;
12455  if(TTClockAdjustCheckBox->Checked)
12456  {
12457  TTClockAdjustWarningHide = true;
12458  }
12459  Utilities->CallLogPop(2219);
12460  }
12461  catch(const Exception &e)
12462  {
12463  ErrorLog(216, e.Message);
12464  }
12465 }
12466 
12467 //---------------------------------------------------------------------------
12468 
12469 void __fastcall TInterface::ConflictAnalysisButtonClick(TObject *Sender)
12470 {
12471  try
12472  {
12473  TrainController->LogEvent("ConflictAnalysisButtonClick");
12474  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConflictAnalysisButtonClick");
12475  ConflictPanel->Visible = true;
12476  Utilities->CallLogPop(2220);
12477  }
12478  catch(const Exception &e)
12479  {
12480  ErrorLog(217, e.Message);
12481  }
12482 }
12483 
12484 //---------------------------------------------------------------------------
12485 
12486 void __fastcall TInterface::CPCancelButtonClick(TObject *Sender)
12487 {
12488  try
12489  {
12490  TrainController->LogEvent("CPCancelButtonClick");
12491  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPCancelButtonClick");
12492  ConflictPanel->Visible = false;
12493  Utilities->CallLogPop(2221);
12494  }
12495  catch(const Exception &e)
12496  {
12497  ErrorLog(218, e.Message);
12498  }
12499 }
12500 
12501 //---------------------------------------------------------------------------
12502 
12503 void __fastcall TInterface::CPGenFileButtonClick(TObject *Sender)
12504 {
12505  try
12506  {
12507  TrainController->LogEvent("CPGenFileButtonClick");
12508  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPGenFileButtonClick");
12509  if(!CPArrivalsCheckBox->Checked && !CPDeparturesCheckBox->Checked && !CPAtLocCheckBox->Checked)
12510  {
12511  ShowMessage("No boxes ticked!");
12512  }
12513  else //keep ticks & range values from last time, only reset on startup
12514  {
12515  Screen->Cursor = TCursor(-11);//hourglass
12516  AnsiString TTTitle;
12518  {
12519  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
12520  {
12521  if(CreateEditTTFileName[x] == '\\')
12522  {
12523  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
12524  break;
12525  }
12526  }
12528  CPAtLocCheckBox->Checked, CPEditArrRange->Text.ToInt(), CPEditDepRange->Text.ToInt()))
12529  {
12530  ShowMessage("Analysis complete and file created");
12531  }
12532  ConflictPanel->Visible = false;
12533  }
12534  }
12535  Screen->Cursor = TCursor(-2);//arrow
12536  Utilities->CallLogPop(2222);
12537  }
12538  catch(const Exception &e)
12539  {
12540  ErrorLog(219, e.Message);
12541  }
12542 }
12543 
12544 //---------------------------------------------------------------------------
12545 // end of fastcalls & directly associated functions
12546 // ---------------------------------------------------------------------------
12547 
12548 void TInterface::SetTopIndex(int Caller)
12549 {
12550 //Set TopIndex to the proper value & also Selected so don't have a different selection to the highlighted entry
12551  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTopIndex");
12552  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < AllEntriesTTListBox->TopIndex)
12553  {
12555  }
12556  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (AllEntriesTTListBox->TopIndex + 45))
12557  {
12558  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
12559  }
12560  else
12561  {
12562  AllEntriesTTListBox->TopIndex = AllEntriesTTListBox->TopIndex;
12563  }
12564  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
12565  Utilities->CallLogPop(2207);
12566 }
12567 
12568 // ---------------------------------------------------------------------------
12569 
12570 void TInterface::ClearandRebuildRailway(int Caller) // now uses HiddenScreen to help avoid flicker
12571 {
12572  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearandRebuildRailway");
12573  bool ClockState = Utilities->Clock2Stopped;
12574 
12575  Utilities->Clock2Stopped = true;
12577  Track->RebuildUserGraphics(0, HiddenDisplay); // new at v2.4.0, plot first so all else overwrites, including the grid if selected
12578  if(ScreenGridFlag && (Level1Mode == TrackMode))
12579  {
12580  int WidthNum = int(MainScreen->Width / 160) + 1;
12581  int HeightNum = int(MainScreen->Height / 144) + 1;
12582  for(int x = 0; x < WidthNum; x++)
12583  {
12584  for(int y = 0; y < HeightNum; y++)
12585  {
12586  HiddenDisplay->PlotAbsolute(0, x * 160, y * 144, RailGraphics->GridBitmap);
12587  }
12588  }
12589  }
12590 
12591 // TextHandler->RebuildFromTextVector(1, HiddenDisplay); //This now incorporated in RebuildTrackAndText so that text is plotted after inactive
12592 // elements but before active elements. This is so text can overwite stations and non-station named locations.
12593 
12595 
12596 // Display->Output->Invalidate(); experiment, needs TDisplay Output to be public. Trying to invoke the white flashes that
12597 // used to occur frequently without Disp->Update() in PlotOriginal
12598 
12599  // OperMode LCs plotted below
12601  {
12603  }
12604 
12605  if(Level1Mode == PrefDirMode)
12606  {
12607  if(EveryPrefDir->PrefDirSize() > 0)
12608  {
12610  }
12612  {
12614  }
12615  }
12616 
12617  if(Level1Mode == TrackMode)
12618  {
12620  {
12621  LocationNameButton->Enabled = true;
12622  }
12623  else
12624  {
12625  LocationNameButton->Enabled = false;
12626  }
12627  }
12628 
12630  {
12632  DistanceKey->Visible = true;
12633  DistancesMarked = true;
12634  LengthConversionPanel->Visible = true;
12635  SpeedConversionPanel->Visible = true;
12636  }
12637 
12638  if(Level2TrackMode == DistanceContinuing) // for extended distances
12639  {
12640  if(ConstructPrefDir->PrefDirSize() > 0)
12641  {
12642  Track->LengthMarker(2, HiddenDisplay); //this line was after the next line until v2.5.1, changed so magenta not overrridden after PrefDirMarker called
12644  DistanceKey->Visible = true;
12645  DistancesMarked = true;
12646  LengthConversionPanel->Visible = true;
12647  SpeedConversionPanel->Visible = true;
12648  }
12649  }
12650 
12652  // this is to keep the distance markers if they are already present when Select is chosen, in case user wishes to choose SelectLengths,
12653  // don't need to display ConstructPrefDir marker as that only needed in DistanceContinuing mode
12654  {
12656  DistanceKey->Visible = true;
12657  }
12658 
12660  // cancel DistancesMarked if exit from any of these modes
12661  {
12662  DistancesMarked = false;
12663  DistanceKey->Visible = false;
12664  LengthConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
12665  SpeedConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
12666  }
12667 
12669  // in process of moving so use NewSelectBitmapHLoc & VLoc
12670  {
12672  }
12673 
12675  // not in process of moving or failed to click mouse within selection so use SelectBitmapHLoc & VLoc
12676  {
12678  }
12679 
12680  if(Level1Mode == OperMode)
12681  {
12683  if(!AllRoutes->LockedRouteVector.empty())
12684  {
12685  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
12686  {
12687  if(!(AllRoutes->TrackIsInARoute(7, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos)))
12688  {
12689  AllRoutes->LockedRouteVector.erase(LRVIT);
12690  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
12691  // hence no longer needed so get rid of it (end of route can't be points, crossover or bridge so danger of
12692  // route being on the other track of a 2-track element doesn't arise)
12693  continue;
12694  }
12695  TOneRoute Route = AllRoutes->GetFixedRouteAt(0, LRVIT->RouteNumber);
12696  int x = Route.PrefDirSize() - 1;
12697  bool BreakFlag = false;
12698  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(1, x);
12699  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
12700  {
12701  HiddenDisplay->PlotOutput(10, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
12702  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
12703  if(!(AllRoutes->TrackIsInARoute(8, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
12704  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
12705  {
12706  BreakFlag = true;
12707  break; // train removed earlier element from route so stop here
12708  }
12709  x--;
12710  if(x < 0) //added after Albie Vowles reported error on 14/08/20 by email
12711  { //it means that part of the route (including that at the truncate point) has been cancelled, in this case by a train running past the signal
12712  BreakFlag = true; //at danger and cancelling the route elements in front of it. The locked route is now too short and this 'while' loop won't find
12713  break; //it, so x keeps decrementing and when it becomes -1 an error is thrown. This addition prevents the error.
12714  }
12715  PrefDirElement = Route.GetFixedPrefDirElementAt(2, x);
12716  }
12717  if(!BreakFlag)
12718  {
12719  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
12720  {
12721  HiddenDisplay->PlotOutput(11, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
12722  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
12723  }
12724  }
12725  }
12726  }
12727 
12728  if(RouteMode == RouteContinuing)
12729  {
12731 // system thinks overlay is already plotted, so plot original to reset the OverlayPlotted flag
12734  if(AutoSigsFlag)
12736  else if(PreferredRoute) //added at v2.7.0, was ConsecSignalsRoute
12738  else
12740  }
12741 
12742  if(Track->PointFlashFlag)
12743  {
12744  // need to reset the screen location for picking up the original graphic
12745  int Left, Top; // Embarcadero change - these missing in error from Borland file
12747  // note that the above Pos values are wrt layout, not the screen, but the Left & Top values are wrt screen
12748  PointFlash->SetSourceRect(Left, Top);
12749  PointFlash->LoadOriginalScreenGraphic(4); // reload from new position
12750  // doesn't matter whether Flash was on or off when this function called as will sort itself out later (may miss a flash but won't be noticeable)
12751  }
12752 
12753  // now plot level crossings (must be after routes). These don't need any base elements to be plotted as they are already plotted.
12754  // In order to avoid plotting the whole LC for every element of a LC a bool value - LCPlotted - is used to save time
12755  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
12756  {
12757  (Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)))->LCPlotted = false;
12758  }
12759  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
12760  {
12761  int BaseSpeedTag;
12762  TTrackElement ATE;
12763  TTrackElement ITE = *(Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)));
12764  {
12765  BaseSpeedTag = Track->GetTrackElementFromTrackMap(0, ITE.HLoc, ITE.VLoc).SpeedTag;
12766  if(ITE.LCPlotted == false)
12767  {
12768  if(ITE.Attribute == 0)
12769  {
12771  }
12772  else if(ITE.Attribute == 1)
12773  {
12774  //need to determine if should plot green (manual) or red (auto), but all linked LCs have ConsecSignals set to 2 in BarriersDownVector if manual
12775  //so just need to test this for the HLoc & VLoc position match
12776  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
12777  {
12778  if((Track->BarriersDownVector.at(x).HLoc == ITE.HLoc) && (Track->BarriersDownVector.at(x).VLoc == ITE.VLoc))
12779  {
12780  if(Track->BarriersDownVector.at(x).TypeOfRoute == 2)
12781  {
12782  Track->PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(0, BaseSpeedTag, ITE.HLoc, ITE.VLoc, HiddenDisplay, true); //true for manual = green
12783  }
12784  else
12785  {
12786  Track->PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(1, BaseSpeedTag, ITE.HLoc, ITE.VLoc, HiddenDisplay, false); //false for auto = red
12787  }
12788  }
12789  }
12790  }
12791  // if ITE->Attribute == 2 then LC is changing, FlashingGraphics will take care of flashing & final plotting,
12792  // it won't set LCPlotted but no real time lost in this case
12793  }
12794  }}
12796  }
12797 
12798  Display->ZoomOutFlag = false;
12799  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomOut");
12800  MainScreen->Picture->Bitmap->Assign(HiddenScreen->Picture->Bitmap);
12801  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
12802  Utilities->Clock2Stopped = ClockState;
12803  Utilities->CallLogPop(91);
12804 }
12805 
12806 // ---------------------------------------------------------------------------
12807 
12808 bool TInterface::HighLightOneGap(int Caller, int &HLoc, int &VLoc)
12809 {
12810  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighLightOneGap");
12811  if(Track->FindAndHighlightAnUnsetGap(1)) // true if find one
12812  {
12813  if(!PreventGapOffsetResetting) // don't reset display position if returning from zoomout mode
12814  {
12815  while((Display->DisplayOffsetH - Track->GetGapHLoc()) > 0)
12816  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
12819  while((Display->DisplayOffsetV - Track->GetGapVLoc()) > 0)
12820  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
12823  }
12824  InfoPanel->Visible = true;
12825  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting element";
12826  ClearandRebuildRailway(31); // get rid of earlier gap selection
12827  Utilities->CallLogPop(92);
12828  return true; // return as one now identified & over to MainScreenMouseDown with Level2TrackMode = GapSetting
12829  }
12830  Utilities->CallLogPop(93);
12831  return false; // no unset ones left to find
12832 }
12833 
12834 // ---------------------------------------------------------------------------
12835 
12837 {
12838  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearEverything");
12839  if(FileChangedFlag)
12840  {
12841  UnicodeString MessageStr = "The railway has changed, close it without saving?";
12842  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
12843  if(button == IDNO)
12844  {
12845  Utilities->CallLogPop(1140);
12846  return false;
12847  }
12848  }
12849  Display->ClearDisplay(7);
12851 
12852  Display->DisplayOffsetH = 0;
12853  Display->DisplayOffsetV = 0;
12858 
12859 // these ensure that all persistent vectors, maps & multimaps etc are cleared
12860  delete TrainController;
12861  delete EveryPrefDir;
12862  delete ConstructRoute;
12863  delete ConstructPrefDir;
12864  delete AllRoutes;
12865  delete Track;
12866  delete TextHandler;
12867 // NB can't delete & recreate Utilities or will lose the CallLog file & have errors due to log being empty when try to
12868 // pop earlier pushed values
12869 // OK though as no containers in Utilities that need to clear & PerformanceFile recreated when begin to operate a later
12870 // railway
12871  TextHandler = new TTextHandler;
12872  Track = new TTrack;
12873  AllRoutes = new TAllRoutes;
12875  ConstructRoute = new TOneRoute;
12876  EveryPrefDir = new TOnePrefDir;
12878  PerformanceLogBox->Lines->Clear();
12879  ResetAll(1);
12880  Utilities->CallLogPop(94);
12881  return true;
12882 }
12883 
12884 // ---------------------------------------------------------------------------
12885 
12886 bool TInterface::FileIntegrityCheck(int Caller, char *FileName) const // true for success
12887 {
12888  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FileIntegrityCheck," + AnsiString(FileName));
12889  std::ifstream VecFile(FileName);
12890 
12891  if(VecFile.is_open())
12892  {
12893  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // Program version
12894  {
12895  VecFile.close();
12896  Utilities->CallLogPop(1805);
12897  return false;
12898  }
12899  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetHHome
12900  {
12901  VecFile.close();
12902  Utilities->CallLogPop(1440);
12903  return false;
12904  }
12905  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetVHome
12906  {
12907  VecFile.close();
12908  Utilities->CallLogPop(1441);
12909  return false;
12910  }
12911  bool GraphicsFollow = false;
12912  int NumberOfActiveElements;
12913  if(!(Track->CheckTrackElementsInFile(1, NumberOfActiveElements, GraphicsFollow, VecFile))) // for new loads
12914  {
12915  VecFile.close();
12916  Utilities->CallLogPop(95);
12917  return false;
12918  }
12919  if(!(TextHandler->CheckTextElementsInFile(0, VecFile)))
12920  {
12921  VecFile.close();
12922  Utilities->CallLogPop(96);
12923  return false;
12924  }
12925  if(!(EveryPrefDir->CheckOnePrefDir(0, NumberOfActiveElements, VecFile)))
12926  {
12927  VecFile.close();
12928  Utilities->CallLogPop(97);
12929  return false;
12930  }
12931  if(GraphicsFollow)
12932  {
12933  if(!Track->CheckUserGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
12934  {
12935  VecFile.close();
12936  Utilities->CallLogPop(2186);
12937  return false;
12938  }
12939  }
12940  VecFile.close();
12941  }
12942  else
12943  {
12944  Utilities->CallLogPop(1153);
12945  return false;
12946  }
12947  Utilities->CallLogPop(98);
12948  return true;
12949 }
12950 
12951 // ---------------------------------------------------------------------------
12952 
12953 void TInterface::Delay(int Caller, double Msec)
12954 {
12955  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Delay," + AnsiString(Msec));
12956  TDateTime First, Second;
12957  bool Finished = false;
12958 
12959  First = TDateTime::CurrentDateTime();
12960  double TimeVal1 = 86400000 * double(First); // no of msec in a day
12961 
12962  while(!Finished)
12963  {
12964  Second = TDateTime::CurrentDateTime();
12965  double TimeVal2 = 86400000 * double(Second);
12966  if((TimeVal2 - TimeVal1) > Msec)
12967  Finished = true;
12968  }
12969  Utilities->CallLogPop(1203);
12970 }
12971 
12972 // ---------------------------------------------------------------------------
12973 
12975 {
12976  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetCurrentSpeedButton");
12977  if(CurrentSpeedButton)
12978  CurrentSpeedButton->Down = false;
12979  CurrentSpeedButton = 0;
12980  Utilities->CallLogPop(1204);
12981 }
12982 
12983 // ---------------------------------------------------------------------------
12984 
12986 {
12987  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MovingTrainPresentOnFlashingRoute");
12988  int TrainID;
12989 
12990  if(ConstructRoute->SearchVectorSize() == 0)
12991  {
12992  Utilities->CallLogPop(99);
12993  return false;
12994  }
12995  for(unsigned int x = 0; x < ConstructRoute->SearchVectorSize(); x++)
12996  {
12997  TPrefDirElement PrefDirElement = ConstructRoute->GetFixedSearchElementAt(14, x);
12998  if(PrefDirElement.TrackType == Bridge)
12999  {
13000  if(PrefDirElement.GetXLinkPos() < 2)
13001  TrainID = Track->TrackElementAt(486, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos01;
13002  else
13003  TrainID = Track->TrackElementAt(487, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos23;
13004  }
13005  else
13006  TrainID = Track->TrackElementAt(488, PrefDirElement.GetTrackVectorPosition()).TrainIDOnElement;
13007  if((TrainID > -1) && !(TrainController->TrainVectorAtIdent(4, TrainID).Stopped()))
13008  {
13009  Utilities->CallLogPop(100);
13010  return true;
13011  }
13012  // check for crossed diagonal fouling by train added at v1.2.0
13013  int TrainID; // not used
13014  int LinkNumber1 = PrefDirElement.Link[PrefDirElement.GetELinkPos()];
13015  int LinkNumber2 = PrefDirElement.Link[PrefDirElement.GetXLinkPos()];
13016  if((LinkNumber1 == 1) || (LinkNumber1 == 3) || (LinkNumber1 == 7) || (LinkNumber1 == 9))
13017  {
13018  if(Track->DiagonalFouledByTrain(1, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber1, TrainID))
13019  {
13020  Utilities->CallLogPop(2037);
13021  return true;
13022  }
13023  }
13024  if((LinkNumber2 == 1) || (LinkNumber2 == 3) || (LinkNumber2 == 7) || (LinkNumber2 == 9))
13025  {
13026  if(Track->DiagonalFouledByTrain(2, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber2, TrainID))
13027  {
13028  Utilities->CallLogPop(2038);
13029  return true;
13030  }
13031  }
13032  }
13033  Utilities->CallLogPop(101);
13034  return false;
13035 }
13036 
13037 // ---------------------------------------------------------------------------
13038 
13040 {
13041  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RevertToOriginalRouteSelector");
13042  AutoRouteStartMarker->PlotOriginal(26, Display); // if overlay not plotted will ignore
13043  SigRouteStartMarker->PlotOriginal(27, Display); // if overlay not plotted will ignore
13044  NonSigRouteStartMarker->PlotOriginal(28, Display); // if overlay not plotted will ignore
13045  RouteCancelFlag = false;
13047  {
13048  RouteCancelButton->Enabled = true;
13049  }
13050  else
13051  {
13052  RouteCancelButton->Enabled = false;
13053  }
13056 // reset here so that a n element that has been selected and then not doesn't remain set as a single element
13057  InfoPanel->Visible = true;
13058  if(Level2OperMode != Paused)
13059  {
13060  InfoPanel->Caption = InfoCaptionStore;
13061  }
13062  Utilities->CallLogPop(102);
13063 }
13064 
13065 // ---------------------------------------------------------------------------
13066 
13067 // usermode functions below
13069 {
13070  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel1Mode");
13071  if(!Display->ZoomOutFlag)
13072  {
13075  Track->GapFlashFlag = false;
13076  }
13077 // GapFlash resets when any mode selected unless zoomed out
13078 // note that if selecting zoom back in then this will be called before ZoomOutFlag is reset so won't
13079 // reset GapFlashFlag
13080  switch(Level1Mode) // use the data member
13081  {
13082  case BaseMode:
13083  CopyMenuItem->ShortCut = TextToShortCut(""); // added these for v2.1.0 to set default values after use of the 'Edit' menu during track building
13084  CutMenuItem->ShortCut = TextToShortCut(""); // to allow normal cutting/copying/pasting, especially in timetable construction or editing
13085  PasteMenuItem->ShortCut = TextToShortCut("");
13090  LengthConversionPanel->Visible = false;
13091  SpeedConversionPanel->Visible = false;
13092  TimetableEditPanel->Visible = false;
13093  TrainController->TTEditPanelVisible = false; //added at v2.6.0 for two location message
13094  TrackBuildPanel->Visible = false;
13095  TrackElementPanel->Visible = false;
13096  LocationNameTextBox->Visible = false;
13097  TextBox->Visible = false;
13098  TrackLengthPanel->Visible = false;
13099  InfoPanel->Visible = false;
13100  PrefDirPanel->Visible = false;
13101  TimetablePanel->Visible = false;
13102  OperatingPanel->Visible = false;
13103  PrefDirKey->Visible = false;
13104  TrackLinkedImage->Visible = false;
13105  TrackNotLinkedImage->Visible = false;
13106  GapsSetImage->Visible = false;
13107  GapsNotSetImage->Visible = false;
13108  LocationNamesSetImage->Visible = false;
13109  LocationNamesNotSetImage->Visible = false;
13110  ModeMenu->Enabled = true;
13111  FileMenu->Enabled = true;
13112  EditMenu->Enabled = false;
13113  BuildTrackMenuItem->Enabled = true;
13114  SigAspectButton->Enabled = false;
13115  Track->ChangingLCVector.clear();
13116  Track->BarriersDownVector.clear();
13118  ConverttoRightHandSignalsMenuItem->Enabled = false; // new at v2.3.0
13119  SigImagePanel->Visible = false; // new at v2.3.0
13120  MTBFEditBox->Visible = false; // new at v2.4.0
13121  MTBFLabel->Visible = false;
13122  TTClockAdjustWarningPanel->Visible = false;
13123  if(Track->IsTrackFinished())
13124  {
13125  PlanPrefDirsMenuItem->Enabled = true;
13126  if(TimetableTitle != "")
13127  {
13128  OperateRailwayMenuItem->Enabled = true;
13129  }
13130  else
13131  {
13132  OperateRailwayMenuItem->Enabled = false;
13133  }
13134  }
13135  else
13136  {
13137  PlanPrefDirsMenuItem->Enabled = false;
13138  OperateRailwayMenuItem->Enabled = false;
13139  }
13140  if(RlyFile)
13141  {
13142  LoadTimetableMenuItem->Enabled = true;
13143  }
13144  else
13145  {
13146  LoadTimetableMenuItem->Enabled = false;
13147  }
13148  LoadRailwayMenuItem->Enabled = true;
13149  if(NoRailway())
13150  {
13151  SaveAsMenuItem->Enabled = false;
13152  ImageMenu->Enabled = false;
13153  SaveImageAndGridMenuItem->Enabled = false;
13154  SaveImageNoGridMenuItem->Enabled = false;
13155  SaveImageAndPrefDirsMenuItem->Enabled = false;
13156  SaveOperatingImageMenuItem->Enabled = false;
13157  BlackBgndMenuItem->Enabled = false;
13158  WhiteBgndMenuItem->Enabled = false;
13159  BlueBgndMenuItem->Enabled = false;
13160  ConverttoRightHandSignalsMenuItem->Enabled = true; // new at v2.3.0
13161  SigImagePanel->Visible = true; // new at v2.3.0
13162  if(Utilities->clTransparent != TColor(0))
13163  {
13164  BlackBgndMenuItem->Enabled = true;
13165  }
13166  if(Utilities->clTransparent != TColor(0xFFFFFF))
13167  {
13168  WhiteBgndMenuItem->Enabled = true;
13169  }
13170  if(Utilities->clTransparent != TColor(0x330000))
13171  {
13172  BlueBgndMenuItem->Enabled = true;
13173  }
13174  ClearAllMenuItem->Enabled = false;
13175  InfoPanel->Visible = true;
13176  InfoPanel->Caption = "Select an option from the File, Mode or Help menus";
13177  }
13178  else
13179  {
13180  InfoPanel->Visible = false;
13181  SaveAsMenuItem->Enabled = true;
13182  ImageMenu->Enabled = true;
13183  SaveImageAndGridMenuItem->Enabled = true;
13184  SaveImageNoGridMenuItem->Enabled = true;
13185  if(EveryPrefDir->PrefDirSize() > 0)
13186  SaveImageAndPrefDirsMenuItem->Enabled = true;
13187  else
13188  SaveImageAndPrefDirsMenuItem->Enabled = false;
13189  BlackBgndMenuItem->Enabled = false;
13190  WhiteBgndMenuItem->Enabled = false;
13191  BlueBgndMenuItem->Enabled = false;
13192  SaveOperatingImageMenuItem->Enabled = false;
13193  ClearAllMenuItem->Enabled = true;
13194  }
13195  if(SavedFileName == "")
13196  {
13197  SaveMenuItem->Enabled = false;
13198  }
13199  else if(!FileChangedFlag)
13200  {
13201  SaveMenuItem->Enabled = false;
13202  }
13203  else if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
13204  {
13205  if(!(Track->IsReadyForOperation(false)))
13206  {
13207  SaveMenuItem->Enabled = false; // can't save under its old name as not now a .rly file
13208  }
13209  else
13210  {
13211  SaveMenuItem->Enabled = true; // must have changed some of the PrefDirs (because FileChangedFlag is true)
13212  }
13213  }
13214  else
13215  {
13216  SaveMenuItem->Enabled = true;
13217  }
13218  LoadSessionMenuItem->Enabled = true;
13219  ExitMenuItem->Enabled = true;
13220  ScreenGridFlag = false;
13221  TrainController->CrashWarning = false;
13222  TrainController->DerailWarning = false;
13223  TrainController->SPADWarning = false;
13225  TrainController->CallOnWarning = false;
13228  UserGraphicReselectPanel->Visible = false;
13229  ClearandRebuildRailway(32); // to get rid of unwanted displays (eg distance markers)
13230  SetTrackBuildImages(13);
13231  break;
13232 
13233  case TimetableMode:
13237  ModeMenu->Enabled = false;
13238  SigImagePanel->Visible = false; // new at v2.3.0
13239  FileMenu->Enabled = false;
13240  EditMenu->Enabled = false;
13241  FloatingInfoMenu->Enabled = false;
13242  ImageMenu->Enabled = false;
13243  TimetableEditPanel->BringToFront();
13244  TimetableHandler();
13245  break;
13246 
13247  case TrackMode:
13248  if(Level2TrackMode == CutMoving)
13249  {
13250  Level2TrackMode = Pasting; // paste the selection
13251  SetLevel2TrackMode(52);
13252  }
13257  TrackBuildPanel->Visible = true;
13258  TrackBuildPanelLabel->Caption = "Build/modify";
13259  TrackElementPanel->Visible = false;
13260  TrackLengthPanel->Visible = false;
13261  PrefDirPanel->Visible = false;
13262  TimetablePanel->Visible = false;
13263  OperatingPanel->Visible = false;
13264  InfoPanel->Visible = false;
13265  InfoPanel->Caption = "";
13266  LocationNameTextBox->Visible = false;
13267  TextBox->Visible = false;
13268  ModeMenu->Enabled = false;
13269  SigImagePanel->Visible = false; // new at v2.3.0
13270  FileMenu->Enabled = false;
13271  // set edit menu items
13273  // track buttons
13274  AddTrackButton->Enabled = true;
13276  {
13277  LocationNameButton->Enabled = true;
13278  }
13279  else
13280  {
13281  LocationNameButton->Enabled = false;
13282  }
13283  ScreenGridButton->Enabled = true;
13284  ExitTrackButton->Enabled = true;
13285  SetGapsButton->Enabled = false;
13286  TrackOKButton->Enabled = false;
13287  if(Track->GapsUnset(5))
13288  {
13289  SetGapsButton->Enabled = true;
13290  }
13291  // only enable if there are gaps still to be set (returns false for no track)
13292  else
13293  {
13294  if(!(Track->NoActiveTrack(2)) && !(Track->IsTrackFinished()))
13295  {
13296  TrackOKButton->Enabled = true;
13297  }
13298  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
13299  }
13300  SetLengthsButton->Enabled = false;
13301  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
13302  {
13303  SetLengthsButton->Enabled = true;
13304  }
13305  // text buttons
13306  AddTextButton->Enabled = true;
13307  TextOrUserGraphicGridButton->Enabled = true;
13308  FontButton->Enabled = true;
13309  MoveTextOrGraphicButton->Enabled = false;
13310  if(TextHandler->TextVectorSize(9) > 0)
13311  {
13312  MoveTextOrGraphicButton->Enabled = true;
13313  }
13314  if(!Track->UserGraphicVector.empty())
13315  {
13316  MoveTextOrGraphicButton->Enabled = true;
13317  }
13318  SelectionValid = false;
13320  TimetableTitle = "";
13321  SetCaption(0);
13322  break;
13323 
13324  case PrefDirMode:
13328  PrefDirPanel->Visible = true;
13329  PrefDirPanelLabel->Caption = "Preferred direction selection";
13330 
13331  InfoPanel->Visible = true;
13332  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select preferred direction start location (right click to erase)";
13333  PrefDirKey->Visible = true;
13334  ModeMenu->Enabled = false;
13335  SigImagePanel->Visible = false; // new at v2.3.0
13336  FileMenu->Enabled = false;
13337 // set edit menu items
13339  AddPrefDirButton->Enabled = false;
13340  DeleteOnePrefDirButton->Enabled = false;
13342  if(EveryPrefDir->PrefDirSize() > 0)
13343  {
13344  DeleteAllPrefDirButton->Visible = true;
13345  DeleteAllPrefDirButton->Enabled = true;
13346  SaveImageAndPrefDirsMenuItem->Enabled = true;
13347  }
13348  else
13349  {
13350  DeleteAllPrefDirButton->Enabled = false;
13351  SaveImageAndPrefDirsMenuItem->Enabled = false;
13352  }
13353  ExitPrefDirButton->Enabled = true;
13354  ClearandRebuildRailway(33); // to mark PrefDirs & clear earlier PrefDir markers
13355 // TimetableTitle = ""; no need to unload timetable if only PrefDirs being changed
13356 // SetCaption();
13357  break;
13358 
13359  case OperMode: // if there are any PrefDirs, set to SigPref, else to NoSigNonPref; start in Paused mode
13363  OperatingPanel->Visible = true;
13364  OperatingPanelLabel->Caption = "Operation";
13365 
13366  CallingOnButton->Visible = false;
13367  PresetAutoSigRoutesButton->Visible = true;
13368  PresetAutoSigRoutesButton->Enabled = true;
13369  InfoPanel->Visible = true;
13370  SigImagePanel->Visible = false; // new at v2.3.0
13371  ModeMenu->Enabled = false;
13372  FileMenu->Enabled = false;
13373  EditMenu->Enabled = false;
13374  ImageMenu->Enabled = true;
13375  SaveImageAndGridMenuItem->Enabled = true;
13376  SaveImageNoGridMenuItem->Enabled = true;
13377  if(EveryPrefDir->PrefDirSize() > 0)
13378  SaveImageAndPrefDirsMenuItem->Enabled = true;
13379  else
13380  SaveImageAndPrefDirsMenuItem->Enabled = false;
13381  SaveOperatingImageMenuItem->Enabled = true;
13382  AutoSigsFlag = false;
13383  MTBFEditBox->Visible = true; // visible at pre-start whether any value set or not, so can set a value if required
13385  {
13386  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
13387  }
13388  else
13389  {
13390  MTBFEditBox->Text = "";
13391  }
13392  MTBFEditBox->ReadOnly = false; // because this is prestart mode
13393  MTBFLabel->Visible = true;
13394  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13396  if(EveryPrefDir->PrefDirSize() > 0)
13397  {
13398  ConsecSignalsRoute = true; //default starting conditions
13399  PreferredRoute = true; //default starting conditions
13400  }
13401  else // no PrefDirs
13402  {
13403  ConsecSignalsRoute = false;
13404  PreferredRoute = false;
13405  }
13406 
13407  OperateButton->Enabled = true;
13408  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
13409  ExitOperationButton->Enabled = true;
13410  TTClockAdjButton->Enabled = true;
13411  ShowPerformancePanel = false;
13412  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
13413  ShowOperatorActionPanel = false; // new at v2.2.0
13414  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
13415 
13417 
13418  Utilities->Clock2Stopped = false;
13422  TTClockSpeed = 1;
13423  TTClockSpeedLabel->Caption = "x1";
13426 
13427  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
13428  // format "16/06/2009 20:55:17"
13429  // avoid characters in filename:= / \ : * ? " < > |
13430  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " + TimetableTitle + ".txt";
13431 
13432  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
13433  if(Utilities->PerformanceFile.fail())
13434  {
13435  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
13436  " in the folder where the 'Railway.exe' program file resides");
13437  }
13439 // DisableRouteButtons(2); enable route setting or pre-start
13440 // DisablePanelsStoreMainMenuStates();
13441  TrainController->ContinuationAutoSigVector.clear(); // for restarting after earlier run
13442  AllRoutes->LockedRouteVector.clear(); // for restarting after earlier run
13443 // TrainController->Operate(1);//plot trains that are present at TT start time, ready for running - no, allow route plotting prior to train entries
13444 
13445 // reset all performance indicators
13469 
13470  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
13471  OAListBox->Clear();
13472  OAListBox->Items->Add(L""); // hints for OpActionPanel
13473  OAListBox->Items->Add(L"");
13474  OAListBox->Items->Add(L"");
13475  OAListBox->Items->Add(L"Left click");
13476  OAListBox->Items->Add(L"headcode to");
13477  OAListBox->Items->Add(L"locate train");
13478  OAListBox->Items->Add(L"");
13479  OAListBox->Items->Add(L"");
13480  OAListBox->Items->Add(L"Right click");
13481  OAListBox->Items->Add(L"headcode for");
13482  OAListBox->Items->Add(L"information");
13483  OAListBox->Items->Add(L"");
13484  OAListBox->Items->Add(L"");
13485  OAListBox->Items->Add(L"Left click and");
13486  OAListBox->Items->Add(L"hold grey area");
13487  OAListBox->Items->Add(L"to move panel");
13488 
13489  ClearandRebuildRailway(55); // so points display with one fillet
13490  break;
13491 
13492  case RestartSessionOperMode: // restart in Paused mode after a session load, sets both Level1Mode & Level2OperMode
13493  Level1Mode = OperMode;
13494 // Level2OperMode = Paused; this is now loaded during LoadInterface & could be PreStart of Paused
13497  OperatingPanel->Visible = true;
13498  OperatingPanelLabel->Caption = "Operation";
13499 
13500  CallingOnButton->Visible = true;
13501  PresetAutoSigRoutesButton->Visible = false;
13502  InfoPanel->Visible = true;
13503  ModeMenu->Enabled = false;
13504  SigImagePanel->Visible = false; // new at v2.3.0
13505  FileMenu->Enabled = false;
13506  EditMenu->Enabled = false;
13507  ImageMenu->Enabled = true;
13508  SaveImageAndGridMenuItem->Enabled = true;
13509  SaveImageNoGridMenuItem->Enabled = true;
13510  if(EveryPrefDir->PrefDirSize() > 0)
13511  SaveImageAndPrefDirsMenuItem->Enabled = true;
13512  else
13513  SaveImageAndPrefDirsMenuItem->Enabled = false;
13514  SaveOperatingImageMenuItem->Enabled = true;
13515 
13516  OperateButton->Enabled = true;
13517  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
13518  ExitOperationButton->Enabled = true;
13519  TTClockAdjButton->Enabled = true;
13522  if(Level2OperMode == Paused)
13523  DisableRouteButtons(3); // could be PreStart or Paused
13528  TTClockSpeed = 1;
13529  TTClockSpeedLabel->Caption = "x1";
13531  ShowPerformancePanel = false; // added at v2.2.0
13532  ShowOperatorActionPanel = false; // new at v2.2.0
13533  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
13534  OAListBox->Clear();
13535  OAListBox->Items->Add(L""); // hints for OpActionPanel
13536  OAListBox->Items->Add(L"");
13537  OAListBox->Items->Add(L"");
13538  OAListBox->Items->Add(L"Left click");
13539  OAListBox->Items->Add(L"headcode to");
13540  OAListBox->Items->Add(L"locate train");
13541  OAListBox->Items->Add(L"");
13542  OAListBox->Items->Add(L"");
13543  OAListBox->Items->Add(L"Right click");
13544  OAListBox->Items->Add(L"headcode for");
13545  OAListBox->Items->Add(L"information");
13546  OAListBox->Items->Add(L"");
13547  OAListBox->Items->Add(L"");
13548  OAListBox->Items->Add(L"Left click and");
13549  OAListBox->Items->Add(L"hold grey area");
13550  OAListBox->Items->Add(L"to move panel");
13551  if((TrainController->AvHoursIntValue > 0) || (Level2OperMode == PreStart)) // only visible if already set or if still in prestart mode
13552  {
13553  MTBFEditBox->Visible = true;
13555  {
13556  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
13557  }
13558  else
13559  {
13560  MTBFEditBox->Text = "";
13561  }
13562  MTBFEditBox->ReadOnly = false; // because this is still prestart mode
13563  MTBFLabel->Visible = true;
13564  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13566  }
13567  else
13568  {
13569  MTBFEditBox->Visible = false;
13570  MTBFEditBox->Text = "";
13571  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
13572  MTBFLabel->Visible = false;
13573  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13575  }
13576  break;
13577 
13578  default:
13579  // No further recursion in BaseMode so OK
13580  Level1Mode = BaseMode;
13581  SetLevel1Mode(29);
13582  break;
13583  }
13584  Utilities->CallLogPop(103);
13585 }
13586 
13587 // ---------------------------------------------------------------------------
13588 
13590 {
13591  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2TrackMode");
13592  if(Level1Mode != TrackMode)
13593  {
13594  // No further recursion in BaseMode so OK
13595  Level1Mode = BaseMode;
13596  SetLevel1Mode(20);
13597  Utilities->CallLogPop(1115);
13598  return;
13599  }
13601  {
13602  Utilities->CallLogPop(104);
13603  return;
13604  }
13605  switch(Level2TrackMode) // use the data member
13606  {
13607  case AddTrack:
13609  InfoPanel->Visible = true;
13610  InfoPanel->Caption = "ADDING TRACK: Select element then left click to add it. Right click an element to remove it.";
13611  LengthConversionPanel->Visible = false; // in case had been in distance setting mode
13612  SpeedConversionPanel->Visible = false; // in case had been in distance setting mode
13613  TrackElementPanel->Visible = true;
13614  TrackElementPanel->Enabled = true;
13615  SigAspectButton->Visible = true;
13616  SigAspectButton->Enabled = true;
13617  ClearandRebuildRailway(34); // to replot grid if required & clear any other unwanted items
13619  SetLengthsButton->Enabled = false;
13620  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
13621  {
13622  SetLengthsButton->Enabled = true;
13623  }
13624  UserGraphicReselectPanel->Visible = false;
13625  SelectLengthsFlag = false; // in case still set though probably won't be
13626  EditMenu->Enabled = true; //added at v2.6.0 to allow edits for an empty screen so track elements can fill a selected area
13627  break;
13628 
13629  case AddGraphic:
13630  InfoPanel->Visible = true;
13631  InfoPanel->Caption = "ADDING GRAPHIC: Left click layout to add SELECTED graphic, right click to remove ANY graphic.";
13632  break;
13633 
13634  case SelectGraphic:
13635  InfoPanel->Visible = true;
13636  InfoPanel->Caption = "SELECTING USER GRAPHIC: Select the graphic file then add as many as necessary to the layout.";
13637  break;
13638 
13639  case GapSetting:
13640  int HLoc, VLoc, Count;
13641  Count = Track->NumberOfGaps(0);
13642  if(div(Count, 2).rem == 1) // condition OK
13643  {
13644  ShowMessage("Can't connect, there are an odd number of gaps");
13646  SetLevel1Mode(77);
13648  // No further recursion in AddTrack so OK
13649  SetLevel2TrackMode(40);
13650  Utilities->CallLogPop(105);
13651  return;
13652  }
13653  if(!HighLightOneGap(2, HLoc, VLoc)) // condition OK
13654  // need to call this here to start gap setting process off,
13655  // called in MainScreenMouseDown hereafter. Function returns false for either a LocError (links not yet
13656  // complete) or no more gaps to be highlighted
13657  {
13658  // shouldn't reach here as later gaps covered in MainScreenMouseDown but leave & give error message
13659  ShowMessage("Error - Even number of gaps but all set after first call to HighLightOneGap");
13661  SetLevel1Mode(78);
13663  // No further recursion in AddTrack so OK
13664  SetLevel2TrackMode(41);
13665  Utilities->CallLogPop(106);
13666  return; // all gaps set
13667  }
13668  InfoPanel->Visible = true;
13669  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting gap";
13670  UserGraphicReselectPanel->Visible = false;
13672  break;
13673 
13674  case AddText:
13675  InfoPanel->Visible = true;
13676  InfoPanel->Caption = "ADDING/EDITING TEXT: Left click to add, right click first letter to erase, or left click first letter to edit)";
13677  if(TextHandler->TextVectorSize(13) > 0)
13678  {
13679  MoveTextOrGraphicButton->Enabled = true;
13680  }
13681  else
13682  {
13683  MoveTextOrGraphicButton->Enabled = false;
13684  }
13685  UserGraphicReselectPanel->Visible = false;
13686  ClearandRebuildRailway(58); // to drop DistanceKey if was displayed
13687  break;
13688 
13689  case MoveTextOrGraphic:
13690  InfoPanel->Visible = true;
13691  InfoPanel->Caption = "MOVING TEXT OR GRAPHIC: If text left click first letter, if graphic left click anywhere, then drag";
13692  UserGraphicReselectPanel->Visible = false;
13693  ClearandRebuildRailway(59); // to drop DistanceKey if was displayed
13694  break;
13695 
13696  case AddLocationName:
13697  InfoPanel->Visible = true;
13698  InfoPanel->Caption = "NAMING LOCATIONS: Click on location element to add or change name";
13699  ClearandRebuildRailway(35); // to get rid of earlier red rectangle
13700  UserGraphicReselectPanel->Visible = false;
13701  SetTrackBuildImages(12);
13702  break;
13703 
13704  case DistanceStart:
13705  InfoPanel->Visible = true;
13706  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select first location (only non-default elements marked)";
13707  DistanceKey->Visible = true;
13708  LengthConversionPanel->Visible = true;
13709  SpeedConversionPanel->Visible = true;
13710  UserGraphicReselectPanel->Visible = false;
13711  ClearandRebuildRailway(36); // to get rid of earlier unwanted markings
13712  break;
13713 
13714  case DistanceContinuing:
13715  InfoPanel->Visible = true;
13716  if(ConstructPrefDir->PrefDirSize() == 1)
13717  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select next location";
13718  else
13719  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
13720  UserGraphicReselectPanel->Visible = false;
13721  ClearandRebuildRailway(54); // to remove earlier end marker if present
13722  break;
13723 
13724  case TrackSelecting:
13725  Track->CopyFlag = false;
13726  if(!SelectionValid)
13727  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay
13728  // the old SelectRect (only called when entered from SelectMenuItemClick, & not from
13729  // ReselectMenuItemClick)
13730  InfoPanel->Visible = true;
13731  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
13732  SelectMenuItem->Enabled = false;
13733  ReselectMenuItem->Enabled = false;
13734  CancelSelectionMenuItem->Enabled = true;
13735  UserGraphicReselectPanel->Visible = false;
13736  break;
13737 
13738  case CopyMoving:
13739  Track->CopyFlag = true;
13740  InfoPanel->Visible = true;
13741  InfoPanel->Caption = "COPYING: Left click in selection && drag";
13742  CutMenuItem->Enabled = false;
13743  CopyMenuItem->Enabled = false;
13744  FlipMenuItem->Enabled = false;
13745  MirrorMenuItem->Enabled = false;
13746  RotRightMenuItem->Enabled = false;
13747  RotLeftMenuItem->Enabled = false;
13748  RotateMenuItem->Enabled = false;
13749  PasteMenuItem->Enabled = true;
13750 // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0 - don't allow the option if copying
13751  DeleteMenuItem->Enabled = false;
13752  SelectLengthsMenuItem->Enabled = false;
13753  SelectBiDirPrefDirsMenuItem->Visible = false;
13754  CancelSelectionMenuItem->Enabled = false;
13758  UserGraphicReselectPanel->Visible = false;
13759  break;
13760 
13761  case CutMoving:
13762  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13763  // erase track elements within selected region
13764  Track->CopyFlag = false;
13765  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false; ;
13766  int ErasedTrackVectorPosition;
13767  Screen->Cursor = TCursor(-11); // Hourglass;
13768  InfoPanel->Visible = true;
13769  InfoPanel->Caption = "CUT PROCESSING: Please do not click the mouse";
13770  InfoPanel->Update();
13771  for(int H = SelectRect.left; H < SelectRect.right; H++)
13772  {
13773  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
13774  {
13775  Track->EraseTrackElement(2, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
13776  if(EraseSuccessfulFlag)
13777  {
13778  if(ErasedTrackVectorPosition > -1)
13779  EveryPrefDir->RealignAfterTrackErase(1, ErasedTrackVectorPosition);
13780  NeedToLink = true;
13781  }
13782  }
13783  }
13784  // erase text elements within selected region
13785  int LowSelectHPos = SelectRect.left * 16;
13786  int HighSelectHPos = SelectRect.right * 16;
13787  int LowSelectVPos = SelectRect.top * 16;
13788  int HighSelectVPos = SelectRect.bottom * 16;
13789  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
13790  {
13791  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
13792  TextPtr--) // reverse to prevent skipping during erase
13793  {
13794  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
13795  HighSelectVPos))
13796  {
13797  if(TextHandler->TextErase(1, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
13798  {;
13799  } // unused condition
13800  TextChangesMade = true;
13801  }
13802  }
13803  }
13804  // erase graphic elements that fall wholly within region to be overwritten
13805  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
13806  {
13807  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
13808  GraphicPtr--) // reverse to prevent skipping during erase
13809  {
13810  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
13811  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
13812  {
13813  Track->UserGraphicVector.erase(GraphicPtr);
13814  GraphicChangesMade = true;
13815  }
13816  }
13817  }
13818  Track->CheckMapAndTrack(11); // test
13819  Track->CheckMapAndInactiveTrack(10); // test
13820  Track->CheckLocationNameMultiMap(19); // test
13821  Screen->Cursor = TCursor(-2); // Arrow;
13822  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
13823  // if track not linked to begin with then becomes linked if NeedToLink false
13824  if(NeedToLink)
13825  Track->SetTrackFinished(false); // corrected for v2.1.0
13826  InfoPanel->Caption = "CUTTING: Left click in selection && drag";
13827  CutMenuItem->Enabled = false;
13828  CopyMenuItem->Enabled = false;
13829  FlipMenuItem->Enabled = false;
13830  MirrorMenuItem->Enabled = false;
13831  RotRightMenuItem->Enabled = false;
13832  RotLeftMenuItem->Enabled = false;
13833  RotateMenuItem->Enabled = false;
13834  PasteMenuItem->Enabled = true;
13835 // PasteWithAttributesMenuItem->Enabled = true; //new at v2.2.0 - option enabled if cutting
13836  DeleteMenuItem->Enabled = false;
13837  SelectLengthsMenuItem->Enabled = false;
13838  SelectBiDirPrefDirsMenuItem->Visible = false;
13839  CancelSelectionMenuItem->Enabled = false;
13842  if(NeedToLink || TextChangesMade || GraphicChangesMade)
13843  {
13844  ResetChangedFileDataAndCaption(20, true); // true for NonPrefDirChangesMade
13845  }
13846  ClearandRebuildRailway(37); // to overplot the erased elements with SelectBitmap
13847  UserGraphicReselectPanel->Visible = false;
13849  } break;
13850 
13851  case Pasting:
13852  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13855  int HDiff = SelectBitmapHLoc - SelectRect.left;
13856  int VDiff = SelectBitmapVLoc - SelectRect.top;
13857  bool NeedToLink = false;
13858  bool TrackLinkingRequiredFlag;
13859  Screen->Cursor = TCursor(-11); // Hourglass;
13860  InfoPanel->Visible = true;
13861  InfoPanel->Caption = "PASTING: Please wait";
13862  InfoPanel->Update();
13863 // erase track elements
13864  int LowSelectHLoc = SelectBitmapHLoc;
13865  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
13866  int LowSelectVLoc = SelectBitmapVLoc;
13867  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
13868  bool TrackEraseSuccessfulFlag; // needed but not used here
13869  int ErasedTrackVectorPosition;
13870 // new quick method of erasing, only need H & V values
13871  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
13872  {
13873  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
13874  {
13875  Track->EraseTrackElement(5, x, y, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, false);
13876  if(ErasedTrackVectorPosition > -1)
13877  EveryPrefDir->RealignAfterTrackErase(2, ErasedTrackVectorPosition);
13878  }
13879  }
13880 
13881 // erase text elements that fall within region to be overwritten
13882  int LowSelectHPos = SelectBitmapHLoc * 16;
13883  int HighSelectHPos = (SelectBitmapHLoc * 16) + SelectBitmap->Width;
13884  int LowSelectVPos = SelectBitmapVLoc * 16;
13885  int HighSelectVPos = (SelectBitmapVLoc * 16) + SelectBitmap->Height;
13886  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
13887  {
13888  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
13889  TextPtr--) // reverse to prevent skipping during erase
13890  {
13891  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
13892  HighSelectVPos))
13893  {
13894  if(TextHandler->TextErase(2, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
13895  {;
13896  } // unused condition
13897  }
13898  }
13899  }
13900 // erase graphic elements that fall wholly within region to be overwritten
13901  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
13902  {
13903  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
13904  GraphicPtr--) // reverse to prevent skipping during erase
13905  {
13906  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
13907  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
13908  {
13909  Track->UserGraphicVector.erase(GraphicPtr);
13910  }
13911  }
13912  }
13913  // change the H & V values in SelectVector to the new positions in case Reselect chosen
13914  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
13915  {
13916  Track->SelectVectorAt(35, x).HLoc += HDiff;
13917  Track->SelectVectorAt(1, x).VLoc += VDiff;
13918  }
13919 
13920  // add the new track elements
13921  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
13922  {
13923  if(Track->CopyFlag) // blank all names if copying, lengths & speedlimits stay
13924  {
13925  Track->SelectVectorAt(80, x).LocationName = "";
13927  }
13928  bool InternalChecks = false;
13929 // if(Track->PastingWithAttributes) //new at v2.2.0 to select the new funtion & skip multimap checks //drop in v2.4.0
13930 // {
13932  TrackLinkingRequiredFlag, InternalChecks);
13933  // new at v2.2.0 & used in place of PlotAndAddTrackElement to keep length & speed values
13934 // }
13935 /* drop this in v2.4.0 as all pastes are past with attributes
13936  else //'Aspect' parameter added to PlotAndAdd... at v2.2.0 so can plot signals correctly (always four-aspect before)
13937  {
13938  int Aspect;
13939  if(Track->SelectVectorAt(15, x).TrackType != SignalPost) Aspect = 0; //if an '0' value appears with a SignalPost then must be adding track
13940  //this combination allows the funtion to distinguish between adding track and plotting with attributes
13941  else if(Track->SelectVectorAt(16, x).SigAspect == TTrackElement::GroundSignal) Aspect = 1;
13942  else if(Track->SelectVectorAt(17, x).SigAspect == TTrackElement::TwoAspect) Aspect = 2;
13943  else if(Track->SelectVectorAt(18, x).SigAspect == TTrackElement::ThreeAspect) Aspect = 3;
13944  else Aspect = 4;
13945  Track->PlotAndAddTrackElement(2, Track->SelectVectorAt(19, x).SpeedTag, Aspect, Track->SelectVectorAt(20, x).HLoc, Track->SelectVectorAt(21, x).VLoc, TrackLinkingRequiredFlag, InternalChecks);
13946  }
13947 */
13948  if(TrackLinkingRequiredFlag)
13949  NeedToLink = true;
13950  }
13951 
13952  if(!TextHandler->SelectTextVector.empty()) // skip iteration if empty else have an error
13953  {
13954  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->SelectTextVector.begin(); TextPtr < TextHandler->SelectTextVector.end(); TextPtr++)
13955  {
13956  TextPtr->HPos += HDiff * 16;
13957  TextPtr->VPos += VDiff * 16;
13958  AnsiString TempString = TextPtr->TextString;
13959  // have to create a new TextItem in order to create a new Font object
13960 /* drop in v2.4.0 as all pastes are paste with attributes
13961  if(!Track->PastingWithAttributes) //new at v2.2.0 to deal with the new location prefix '##**' //drop in v2.4.0
13962  {
13963  if(TextPtr->TextString.SubString(1,4) != "##**") //added for named locations so can delete in a simple paste but
13964  //use in PastingWithAttributes
13965  {
13966  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TextPtr->TextString, TextPtr->Font);
13967  TextHandler->TextVectorPush(0, TextItem); //if a normal paste include normal text but not location text
13968  }
13969  else TextPtr->TextString = ""; //delete the name for a simple paste
13970  }
13971 */
13972 // else //if pasting with attributes paste all text but strip the '##**' prefix if present
13973 // {
13974  if(TextPtr->TextString.SubString(1, 4) == "##**")
13975  {
13976  TempString = TextPtr->TextString.SubString(5, TextPtr->TextString.Length()); // don't change SelectTextVector value
13977  if(Track->CopyFlag)
13978  {
13979  TextPtr->TextString = ""; // change SelectTextVector value as reselect shouldn't have locations if copied
13980  TempString = "";
13981  }
13982  }
13983  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TempString, TextPtr->Font);
13985 // }
13986  }
13987  }
13988  // add new graphic items
13989  if(!Track->SelectGraphicVector.empty()) // skip iteration if empty else have an error
13990  { // keep contents of SelectVector valid in case reselect
13991  for(TTrack::TUserGraphicVector::iterator GraphicPtr = Track->SelectGraphicVector.begin(); GraphicPtr < Track->SelectGraphicVector.end();
13992  GraphicPtr++)
13993  {
13994  GraphicPtr->HPos += HDiff * 16; // for reselect
13995  GraphicPtr->VPos += VDiff * 16; // for reselect
13996  Track->UserGraphicVector.push_back(*GraphicPtr);
13997  }
13998  }
13999  Track->SkipLocationNameMultiMapCheck = false; // renamed in v2.4.0 - reset the flag after pasting complete, otherwise multimap checks always skipped
14000  Track->CopyFlag = false;
14001  Track->CheckMapAndTrack(7); // test
14002  Track->CheckMapAndInactiveTrack(7); // test
14003  Track->CheckLocationNameMultiMap(7); // test
14004  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
14005  // if track not linked to begin with then becomes linked if NeedToLink false
14006  if(NeedToLink)
14007  Track->SetTrackFinished(false); // corrected for v2.1.0
14008  Screen->Cursor = TCursor(-2); // Arrow;
14009  SetTrackBuildImages(14);
14012  SetLevel1Mode(79);
14014  // No further recursion in AddTrack so OK
14015  UserGraphicReselectPanel->Visible = false;
14016  SetLevel2TrackMode(42);
14017  } break;
14018 
14019  case Deleting:
14020  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
14021  Track->CopyFlag = false;
14022  UnicodeString MessageStr = "Selected area will be deleted - proceed?";
14023  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
14024  if(button == IDNO)
14025  {
14026  break;
14027  }
14028  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false;
14029  int ErasedTrackVectorPosition;
14030  Screen->Cursor = TCursor(-11); // Hourglass;
14031  InfoPanel->Visible = true;
14032  InfoPanel->Caption = "DELETING: Please wait";
14033  InfoPanel->Update();
14034  for(int H = SelectRect.left; H < SelectRect.right; H++)
14035  {
14036  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
14037  {
14038  Track->EraseTrackElement(3, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
14039  if(EraseSuccessfulFlag)
14040  {
14041  if(ErasedTrackVectorPosition > -1)
14042  EveryPrefDir->RealignAfterTrackErase(3, ErasedTrackVectorPosition);
14043  NeedToLink = true;
14044  }
14045  }
14046  }
14047  // erase text elements that fall within selected region
14048  int LowSelectHPos = SelectRect.left * 16;
14049  int HighSelectHPos = SelectRect.right * 16;
14050  int LowSelectVPos = SelectRect.top * 16;
14051  int HighSelectVPos = SelectRect.bottom * 16;
14052  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
14053  {
14054  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
14055  TextPtr--) // reverse to prevent skipping during erase
14056  {
14057  AnsiString Check = TextPtr->TextString;
14058  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
14059  HighSelectVPos))
14060  {
14061  if(TextHandler->TextErase(3, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
14062  {;
14063  } // unused condition
14064  TextChangesMade = true;
14065  }
14066  }
14067  }
14068  // erase graphic elements that fall within selected region
14069  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
14070  {
14071 
14072 //Isglassen05 (vilhelmgg@gmail.com) reported an error via email and attached an error file on 31/07/20. The error was in the following line which was:
14073 
14074 // for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->SelectGraphicVector.end() - 1); GraphicPtr >= Track->SelectGraphicVector.begin();
14075 // GraphicPtr--) // reverse to prevent skipping during erase
14076 
14077 //i.e if the railway included one or more user graphics but the SelectGraphicVector didn't include any, then GraphicPtr wouldn't point to anything and the program would fail
14078 //corrected 01/08/20 by using UserGraphicVector (as it should have been) for SelectGraphicVector. New version v2.4.3.
14079 
14080  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
14081  GraphicPtr--) // reverse to prevent skipping during erase
14082  {
14083  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
14084  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
14085  {
14086  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = (Track->UserGraphicVector.end() - 1);
14087  UserGraphicPtr >= Track->UserGraphicVector.begin(); UserGraphicPtr--) // reverse to prevent skipping during erase
14088  {
14089  if((UserGraphicPtr->HPos == GraphicPtr->HPos) && (UserGraphicPtr->VPos == GraphicPtr->VPos) &&
14090  (UserGraphicPtr->Width == GraphicPtr->Width) && (UserGraphicPtr->Height == GraphicPtr->Height) &&
14091  (UserGraphicPtr->FileName == GraphicPtr->FileName))
14092  {
14093  Track->UserGraphicVector.erase(UserGraphicPtr);
14094  GraphicChangesMade = true;
14095  }
14096  }
14097  }
14098  }
14099  }
14100  // clear the selectvectors
14102  TextHandler->SelectTextVector.clear();
14103  Track->SelectGraphicVector.clear();
14104  Track->CheckMapAndTrack(10); // test
14105  Track->CheckMapAndInactiveTrack(9); // test
14106  Track->CheckLocationNameMultiMap(15); // test
14107  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
14108  // if track not linked to begin with then becomes linked if NeedToLink false
14109  if(NeedToLink)
14110  Track->SetTrackFinished(false); // corrected for v2.1.0
14111  if(NeedToLink || TextChangesMade || GraphicChangesMade)
14112  {
14113  ResetChangedFileDataAndCaption(21, true); // true for NonPrefDirChangesMade
14114  }
14115  Screen->Cursor = TCursor(-2); // Arrow;
14118  SetLevel1Mode(80);
14120  // No further recursion in AddTrack so OK
14121  UserGraphicReselectPanel->Visible = false;
14122  SetLevel2TrackMode(43);
14123  } break;
14124 
14125  default:
14126  // No further recursion in TrackMode so OK
14127  Track->CopyFlag = false;
14129  SetLevel1Mode(21);
14130  UserGraphicReselectPanel->Visible = false;
14131  break;
14132  }
14133  Utilities->CallLogPop(107);
14134 }
14135 
14136 // ---------------------------------------------------------------------------
14137 
14139 {
14140  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2PrefDirMode");
14141  if(Level1Mode != PrefDirMode)
14142  {
14143  // No further recursion in BaseMode so OK
14144  Level1Mode = BaseMode;
14145  SetLevel1Mode(22);
14146  Utilities->CallLogPop(108);
14147  return;
14148  }
14150  {
14151  Utilities->CallLogPop(109);
14152  return;
14153  }
14154 
14155  switch(Level2PrefDirMode) // use the data member
14156  {
14157  case PrefDirContinuing:
14158  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
14159  InfoPanel->Visible = true;
14160  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
14161  {
14162  AddPrefDirButton->Enabled = true; // this and the line below are to remove focus from any other button that might have it, prior to
14163  AddPrefDirButton->SetFocus(); // disabling the AddPrefDir button, so pressing enter does nothing, it is reset to the AddPrefDir
14164  }
14165  AddPrefDirButton->Enabled = false; // button later if it becomes enabled
14166  DeleteOnePrefDirButton->Enabled = false;
14167  bool LeadingPointsAtLastElement = false;
14168  if(!ConstructPrefDir->EndPossible(0, LeadingPointsAtLastElement))
14169  {
14170  if(LeadingPointsAtLastElement) // size must be > 1
14171  {
14172  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Can't end on leading points, select next location or truncate";
14173  DeleteOnePrefDirButton->Enabled = true;
14174  }
14175  else // size == 1, DeleteOnePrefDirButton->Enabled remains false
14176  {
14177  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select next preferred direction location (right click to truncate)";
14178  }
14179  }
14180  else // size > 1 & EndPossible
14181  {
14182  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Add selection or select next location (right click to truncate)";
14183  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
14184  {
14185  AddPrefDirButton->Enabled = true;
14186  AddPrefDirButton->SetFocus(); // so can just press 'Enter' key
14187  }
14188  DeleteOnePrefDirButton->Enabled = true;
14189  }
14190  ExitPrefDirButton->Enabled = true;
14191  ClearandRebuildRailway(40); // to show truncated PrefDirs
14192  } break;
14193 
14194  case PrefDirSelecting:
14195  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay the old SelectRect
14196  InfoPanel->Visible = true;
14197  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
14198  SelectMenuItem->Enabled = false;
14199  ReselectMenuItem->Enabled = false;
14200  CancelSelectionMenuItem->Enabled = true;
14201  break;
14202 
14203  default:
14204  // No further recursion in PrefDirMode so OK
14206  SetLevel1Mode(23);
14207  break;
14208  }
14209  Utilities->CallLogPop(110);
14210 }
14211 
14212 // ---------------------------------------------------------------------------
14213 
14215 {
14216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2OperMode");
14217  if(Level1Mode != OperMode)
14218  {
14219  // No further recursion in BaseMode so OK
14220  Level1Mode = BaseMode;
14221  SetLevel1Mode(24);
14222  Utilities->CallLogPop(111);
14223  return;
14224  }
14225  if(Level2OperMode == NoOperMode)
14226  {
14227  Utilities->CallLogPop(112);
14228  return;
14229  }
14230  CallingOnButton->Visible = true;
14231  PresetAutoSigRoutesButton->Visible = false;
14232  switch(Level2OperMode) // use the data member
14233  {
14234  case Operating:
14235  { // have to use braces as otherwise the default case bypasses the initialisation of local variables
14236  OperateButton->Enabled = true;
14237  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
14238  ExitOperationButton->Enabled = true;
14239  TTClockAdjButton->Enabled = false;
14240  if(TTClockSpeed == 2)
14241  TTClockSpeedLabel->Caption = "x2";
14242  else if(TTClockSpeed == 4)
14243  TTClockSpeedLabel->Caption = "x4";
14244  else if(TTClockSpeed == 8)
14245  TTClockSpeedLabel->Caption = "x8";
14246  else if(TTClockSpeed == 16)
14247  TTClockSpeedLabel->Caption = "x16";
14248  else if(TTClockSpeed == 0.5)
14249  TTClockSpeedLabel->Caption = "x1/2";
14250  else if(TTClockSpeed == 0.25)
14251  TTClockSpeedLabel->Caption = "x1/4";
14252  else if(TTClockSpeed == 0.125)
14253  TTClockSpeedLabel->Caption = "x1/8";
14254  else if(TTClockSpeed == 0.0625)
14255  TTClockSpeedLabel->Caption = "x1/16";
14256  else
14257  {
14258  TTClockSpeed = 1;
14259  TTClockSpeedLabel->Caption = "x1";
14260  }
14261  AnsiString TimeMessage = Utilities->Format96HHMMSS(TDateTime(PauseEntryRestartTime)) + ": ";
14263  {
14264  // send message to performance log
14265  if(TTClockSpeed == 2)
14266  Display->PerformanceLog(6, TimeMessage + "Timetable clock speed changed to twice normal");
14267  else if(TTClockSpeed == 4)
14268  Display->PerformanceLog(7, TimeMessage + "Timetable clock speed changed to four times normal");
14269  else if(TTClockSpeed == 8)
14270  Display->PerformanceLog(8, TimeMessage + "Timetable clock speed changed to eight times normal");
14271  else if(TTClockSpeed == 16)
14272  Display->PerformanceLog(9, TimeMessage + "Timetable clock speed changed to sixteen times normal");
14273  else if(TTClockSpeed == 0.5)
14274  Display->PerformanceLog(10, TimeMessage + "Timetable clock speed changed to half normal");
14275  else if(TTClockSpeed == 0.25)
14276  Display->PerformanceLog(11, TimeMessage + "Timetable clock speed changed to quarter normal");
14277  else if(TTClockSpeed == 0.125)
14278  Display->PerformanceLog(14, TimeMessage + "Timetable clock speed changed to one eighth normal");
14279  else if(TTClockSpeed == 0.0625)
14280  Display->PerformanceLog(15, TimeMessage + "Timetable clock speed changed to one sixteenth normal");
14281  else
14282  Display->PerformanceLog(12, TimeMessage + "Timetable clock speed changed to normal");
14283  }
14284  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
14285  if(TTClockTimeChange > 0.000347) // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
14286  {
14287  // send message to performance log
14288  int MinsIncrease = ((TTClockTimeChange * 1440) + 0.5); // add 30 secs to ensure truncates correctly
14289  int HoursIncrease = 0;
14290  while(MinsIncrease >= 60)
14291  {
14292  HoursIncrease++;
14293  MinsIncrease -= 60;
14294  }
14295  if(HoursIncrease == 0)
14296  TimeMessage += "Timetable clock incremented by " + AnsiString(MinsIncrease) + "m";
14297  else if(MinsIncrease == 0)
14298  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h";
14299  else
14300  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h " + AnsiString(MinsIncrease) + "m";
14301  Display->PerformanceLog(13, TimeMessage);
14302  }
14303  WarningHover = false;
14306  {
14307  MTBFEditBox->Visible = true;
14308  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
14309  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
14310  MTBFLabel->Visible = true;
14311  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
14313  }
14314  else
14315  {
14316  MTBFEditBox->Visible = false;
14317  MTBFEditBox->Text = "";
14318  MTBFLabel->Visible = false;
14319  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
14321  }
14322  TrainController->BaseTime = TDateTime::CurrentDateTime();
14323 // StopTTClockFlag already false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
14324  } break;
14325 
14326  case Paused:
14327  OperateButton->Enabled = true;
14328  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
14329  ExitOperationButton->Enabled = true;
14330  TTClockAdjButton->Enabled = true;
14335 // StopTTClockFlag stays false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
14338  break;
14339 
14340  // don't need a separate case for PreStart
14341 
14342  default:
14343  // No further recursion in OperMode so OK
14344  Level1Mode = OperMode;
14345  SetLevel1Mode(25);
14346  break;
14347  }
14348  Utilities->CallLogPop(113);
14349 }
14350 
14351 // ---------------------------------------------------------------------------
14352 
14353 void TInterface::ApproachLocking(int Caller, TDateTime TTClockTime)
14354 {
14355  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ApproachLocking");
14356  float LockDelay = 120.0;
14357 
14358  if(!AllRoutes->LockedRouteVector.empty())
14359  {
14360  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
14361  {
14362  bool BreakFlag = false;
14363  if(AllRoutes->TrackIsInARoute(5, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
14364  {
14365  TOneRoute &Route = AllRoutes->GetModifiableRouteAt(0, LRVIT->RouteNumber);
14366  if((TTClockTime - LRVIT->LockStartTime) > TDateTime(LockDelay / 86400))
14367  {
14368  TrainController->LogEvent("LockedRouteRemoved," + AnsiString(LRVIT->TruncateTrackVectorPosition) + "," +
14369  AnsiString(LRVIT->LastTrackVectorPosition));
14370  while(Route.LastElementPtr(9)->GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
14371  { // examine the element one earlier in the route than the last
14372  if(!(AllRoutes->TrackIsInARoute(6, Route.LastElementPtr(10)->Conn[Route.LastElementPtr(11)->GetELinkPos()],
14373  Route.LastElementPtr(12)->ConnLinkPos[Route.LastElementPtr(13)->GetELinkPos()])))
14374  {
14375  BreakFlag = true;
14376  }
14377  AllRoutes->RemoveRouteElement(1, Route.LastElementPtr(14)->HLoc, Route.LastElementPtr(15)->VLoc, Route.LastElementPtr(16)->GetELink());
14378  if(BreakFlag)
14379  break; // train removed earlier element from route so stop here
14380  }
14381  if(!BreakFlag)
14382  { // still need to remove the element at the TruncateTrackVectorPosition
14383  if(Route.LastElementPtr(17)->GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
14384  {
14385  AllRoutes->RemoveRouteElement(2, Route.LastElementPtr(18)->HLoc, Route.LastElementPtr(19)->VLoc,
14386  Route.LastElementPtr(20)->GetELink());
14387  }
14388  }
14389  AllRoutes->CheckMapAndRoutes(10); // test
14390  AllRoutes->LockedRouteVector.erase(LRVIT);
14391  if(!Display->ZoomOutFlag)
14392  ClearandRebuildRailway(17); // to get rid of route graphics
14394  }
14395  }
14396  else
14397  {
14398  AllRoutes->LockedRouteVector.erase(LRVIT);
14399  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
14400  // hence no longer needed so get rid of it
14401  }
14402  }
14403  }
14404  Utilities->CallLogPop(743);
14405 }
14406 
14407 // ---------------------------------------------------------------------------
14408 
14409 void TInterface::ContinuationAutoSignals(int Caller, TDateTime TTClockTime)
14410 {
14411  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ContinuationAutoSignals");
14413  {
14415  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
14416  AutoSigVectorIT--)
14417  {
14418  // Below added at v2.1.0 to prevent locked autosig continuation routes from clearing signals
14419  // need to identify the Continuation element in the route & check if it's in a locked route. If it is then don't call
14420  // SetTrailingSignalsOnContinuationRoute as all signals must stay red.
14421  TPrefDirElement TempPrefDirElement;
14422  int TempLockedVectorNumber;
14423  int LastRouteElement = AllRoutes->GetFixedRouteAt(220, AutoSigVectorIT->RouteNumber).PrefDirSize() - 1;
14424  int TVNum = AllRoutes->GetFixedRouteAt(221, AutoSigVectorIT->RouteNumber).GetFixedPrefDirElementAt(246, LastRouteElement).GetTrackVectorPosition();
14425  // this will be a continuation (error thrown in SetTrailingSignalsOnContinuationRoute if not) & XLinkPos is always 0 for
14426  // route exiting at a continuation
14427  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(14, TVNum, 0, TempPrefDirElement, TempLockedVectorNumber))
14428  {
14429  continue;
14430  }
14431  // end of additions
14432  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->FirstDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 0))
14433  {
14434  AllRoutes->SetTrailingSignalsOnContinuationRoute(1, AutoSigVectorIT->RouteNumber, 0);
14435  AutoSigVectorIT->AccessNumber++;
14436  continue;
14437  }
14438  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->SecondDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 1))
14439  {
14440  AllRoutes->SetTrailingSignalsOnContinuationRoute(2, AutoSigVectorIT->RouteNumber, 1);
14441  AutoSigVectorIT->AccessNumber++;
14442  continue;
14443  }
14444  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->ThirdDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 2))
14445  {
14446  AllRoutes->SetTrailingSignalsOnContinuationRoute(3, AutoSigVectorIT->RouteNumber, 2);
14447  AutoSigVectorIT->AccessNumber++;
14448  continue;
14449  }
14450  }
14451  // examine all vector for any expired values & erase
14452  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
14453  AutoSigVectorIT--)
14454  {
14455  if(AutoSigVectorIT->AccessNumber > 2)
14456  {
14457  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT); // erase expired entries - reverse interation so OK to erase
14458  }
14459  }
14460  }
14461  Utilities->CallLogPop(744);
14462 }
14463 
14464 // ---------------------------------------------------------------------------
14465 
14467 {
14468  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackTrainFloat");
14469  TPoint MousePoint = Mouse->CursorPos;
14470  int ScreenX = MousePoint.x - MainScreen->ClientOrigin.x;
14471  int ScreenY = MousePoint.y - MainScreen->ClientOrigin.y;
14472 
14473  if(!OAListBoxRightMouseButtonDown && ((ScreenX > (MainScreen->Width - 1)) || (ScreenY > (MainScreen->Height - 1)) || (ScreenX < 0) || (ScreenY < 0)))
14474  {//added !OAListBoxRightMouseButtonDown at v2.7.0 so can still obtain info & move to trains from OAListBox even if they are out of the main screen area
14475  FloatingPanel->Visible = false;
14476  Utilities->CallLogPop(1432);
14477  return;
14478  }
14479 
14480  if(PerformancePanel->Visible)
14481  {
14482  if((MousePoint.x >= PerformancePanel->Left) && (MousePoint.x <= (PerformancePanel->Left + PerformancePanel->Width)) &&
14483  ((MousePoint.y - ClientOrigin.y) >= PerformancePanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
14484  (PerformancePanel->Top + PerformancePanel->Height)))
14485  { // dont show floating window if mouse over performance panel
14486  FloatingPanel->Visible = false;
14487  Utilities->CallLogPop(1715);
14488  return;
14489  }
14490  }
14491 
14492  if(TimetableEditPanel->Visible) // added at v2.5.1 as showed track info behind panel
14493  {
14494  if((MousePoint.x >= TimetableEditPanel->Left) && (MousePoint.x <= (TimetableEditPanel->Left + TimetableEditPanel->Width)) &&
14495  ((MousePoint.y - ClientOrigin.y) >= TimetableEditPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
14496  (TimetableEditPanel->Top + TimetableEditPanel->Height)))
14497  { // dont show floating window if mouse over TimetableEditPanel
14498  FloatingPanel->Visible = false;
14499  Utilities->CallLogPop(2240);
14500  return;
14501  }
14502  }
14503 
14504  AnsiString TrackFloat = "", TrainStatusFloat = "", TrainTTFloat = "";
14505  bool ShowTrackFloatFlag = false, ShowTrainStatusFloatFlag = false, ShowTrainTTFloatFlag = false;
14506  int HLoc, VLoc;
14507 
14508  Track->GetTrackLocsFromScreenPos(4, HLoc, VLoc, ScreenX, ScreenY);
14509 
14510  if(Display->ZoomOutFlag)
14511  {
14512  Utilities->CallLogPop(1123);
14513  return;
14514  }
14515 
14516  bool MouseOverOAPanel = false; // this flag added at v2.7.0 in place of prohibition of all floating windows (which was added at v2.3.0 when Xeon notified me in email of 15/10/19 that they were showing)
14517  if(OperatorActionPanel->Visible)
14518  {
14519  if((MousePoint.x >= OperatorActionPanel->Left) && (MousePoint.x <= (OperatorActionPanel->Left + OperatorActionPanel->Width)) &&
14520  ((MousePoint.y - ClientOrigin.y) >= OperatorActionPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
14521  (OperatorActionPanel->Top + OperatorActionPanel->Height)))
14522  {
14523  MouseOverOAPanel = true;
14524  }
14525  }
14526 
14527  if((TrackInfoOnOffMenuItem->Caption == "Hide") && !MouseOverOAPanel)
14528  //MouseOverOAPanel condit added at v2.7.0 in place of prohibition of all floating windows (which was added at v2.3.0 when Xeon notified me in email of 15/10/19 that they were showing)
14529  {
14530  bool ActiveTrackFoundFlag = false, InactiveTrackFoundFlag = false, TwoTrack = false;
14531  AnsiString Length01Str = "", Length23Str = "", SpeedLimit01Str = "", SpeedLimit23Str = "";
14532  AnsiString StationEntryStopLinkPos1Str = "", StationEntryStopLinkPos2Str = "";
14533  AnsiString ATrackSN = "", ATrackTN = "", IATrackSN = "", LengthAndSpeedCaption = "";
14534  AnsiString SigAspectString = ""; // new at version 0.6
14535  int ActiveVecPos = Track->GetVectorPositionFromTrackMap(5, HLoc, VLoc, ActiveTrackFoundFlag);
14536  TTrack::TIMPair InactiveVecPositions = Track->GetVectorPositionsFromInactiveTrackMap(3, HLoc, VLoc, InactiveTrackFoundFlag);
14537  TTrackElement ActiveTrackElement, InactiveTrackElement;
14538  if(InactiveTrackFoundFlag)
14539  {
14540  InactiveTrackElement = Track->InactiveTrackElementAt(32, InactiveVecPositions.first); // only need one for the name
14541  IATrackSN = InactiveTrackElement.LocationName;
14542  }
14543  if(ActiveTrackFoundFlag)
14544  {
14545  ActiveTrackElement = Track->TrackElementAt(449, ActiveVecPos);
14546  ATrackSN = ActiveTrackElement.LocationName;
14547  StationEntryStopLinkPos1Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos1);
14548  StationEntryStopLinkPos2Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos2);
14549  ATrackTN = ActiveTrackElement.ActiveTrackElementName;
14550  if((ATrackTN != "") && (!InactiveTrackFoundFlag || ((InactiveTrackElement.TrackType != Platform) &&
14551  (InactiveTrackElement.TrackType != NamedNonStationLocation)) ||
14552  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName)))
14553  {
14554  ShowMessage("Error - Track has timetable name without corresponding plat/named loc");
14555  }
14556  if(InactiveTrackFoundFlag && ((InactiveTrackElement.TrackType == Platform) || (InactiveTrackElement.TrackType == NamedNonStationLocation)) &&
14557  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName))
14558  {
14559  ShowMessage("Error - plat/named loc and track have different names, or plat/named loc named but not track");
14560  }
14561  if((ActiveTrackElement.TrackType == Points) || (ActiveTrackElement.TrackType == Bridge) || (ActiveTrackElement.TrackType == Crossover))
14562  {
14563  TwoTrack = true;
14564  }
14565  Length01Str = AnsiString(ActiveTrackElement.Length01);
14566  if(Length01Str == "-1")
14567  Length01Str = "Not Set";
14568  SpeedLimit01Str = AnsiString(ActiveTrackElement.SpeedLimit01);
14569  if(SpeedLimit01Str == "-1")
14570  SpeedLimit01Str = "Not Set";
14571  if(TwoTrack)
14572  {
14573  Length23Str = AnsiString(ActiveTrackElement.Length23);
14574  if(Length23Str == "-1")
14575  Length23Str = "Not Set"; // shouldn't be -1 but leave in
14576  SpeedLimit23Str = AnsiString(ActiveTrackElement.SpeedLimit23);
14577  if(SpeedLimit23Str == "-1")
14578  SpeedLimit23Str = "Not Set"; // shouldn't be -1 but leave in
14579  if((ActiveTrackElement.TrackType == Points) && (ActiveTrackElement.SpeedTag < 132))
14580  {
14581  LengthAndSpeedCaption = "Straight track length = " + Length01Str + " m" + '\n' + "Diverging track length = " + Length23Str + " m" + '\n' +
14582  "Straight track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Diverging track speed limit = " + SpeedLimit23Str + " km/h";
14583  }
14584  else if(ActiveTrackElement.TrackType == Points)
14585  {
14586  LengthAndSpeedCaption = "Left diverging track length = " + Length01Str + " m" + '\n' + "Right diverging track length = " + Length23Str +
14587  " m" + '\n' + "Left diverging track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Right diverging track Speed Limit = " +
14588  SpeedLimit23Str + " km/h";
14589  }
14590  else if(ActiveTrackElement.TrackType == Crossover)
14591  // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
14592  {
14593  if((ActiveTrackElement.SpeedTag == 15) || (ActiveTrackElement.SpeedTag == 46))
14594  {
14595  LengthAndSpeedCaption = "Horizontal track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
14596  "Horizontal track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
14597  }
14598  else if(ActiveTrackElement.SpeedTag == 47)
14599  {
14600  LengthAndSpeedCaption = "Horizontal track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
14601  "Horizontal track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
14602  }
14603  else if(ActiveTrackElement.SpeedTag == 45)
14604  {
14605  LengthAndSpeedCaption = "Vertical track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
14606  "Vertical track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
14607  }
14608  else if(ActiveTrackElement.SpeedTag == 44)
14609  {
14610  LengthAndSpeedCaption = "Vertical track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
14611  "Vertical track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
14612  }
14613  else if(ActiveTrackElement.SpeedTag == 16)
14614  {
14615  LengthAndSpeedCaption = "Top left to bottom right track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str +
14616  " m" + '\n' + "Top left to bottom right track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " +
14617  SpeedLimit23Str + " km/h";
14618  }
14619  }
14620  else // bridge
14621  {
14622  LengthAndSpeedCaption = "Top track length = " + Length01Str + " m" + '\n' + "Bottom track length = " + Length23Str + " m" + '\n' +
14623  "Top track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Bottom track speed limit = " + SpeedLimit23Str + " km/h";
14624  }
14625  }
14626  else
14627  {
14628  LengthAndSpeedCaption = "Track length = " + Length01Str + " m" + '\n' + "Track speed limit = " + SpeedLimit01Str + " km/h";
14629  }
14630  }
14631  if(ActiveTrackFoundFlag)
14632  {
14633  // note that now the "In timetable..." line removed much of the below could be simplified, but leave as is
14634  // in case wish to resurrect this line for any reason
14635  ShowTrackFloatFlag = true;
14636  if(ATrackTN != "") // has a timetable name & therefore has a valid platform or non-station name
14637  {
14638  TrackFloat = "Location = " + ATrackTN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
14639  }
14640  else if(ATrackSN != "") // no timetable name but location name, i.e. a footcrossing
14641  {
14642  TrackFloat = "Location = " + ATrackSN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
14643  }
14644 
14645  else if(InactiveTrackFoundFlag) // no timetable name yet but unnamed inactive element at same location (can't be a parapet if active element there)
14646  {
14647  TrackFloat = "Location unnamed\n" + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
14648  }
14649 
14650  else // no timetable or location name, just track
14651  {
14652  TrackFloat = LengthAndSpeedCaption + '\n' + "Track Element ID = " + AnsiString(ActiveTrackElement.ElementID);
14653  }
14654  if(ActiveTrackElement.TrackType == SignalPost) // new for version 0.6
14655  {
14656  if(ActiveTrackElement.SigAspect == TTrackElement::ThreeAspect)
14657  {
14658  SigAspectString = "\nThree-aspect signal";
14659  }
14660  else if(ActiveTrackElement.SigAspect == TTrackElement::TwoAspect)
14661  {
14662  SigAspectString = "\nTwo-aspect signal";
14663  }
14664  else if(ActiveTrackElement.SigAspect == TTrackElement::GroundSignal)
14665  {
14666  SigAspectString = "\nGround signal";
14667  }
14668  else
14669  {
14670  SigAspectString = "\nFour-aspect signal";
14671  }
14672  TrackFloat += SigAspectString;
14673  }
14674  } // if(ActiveFoundFlag)
14675  else if(InactiveTrackFoundFlag) // inactive element but no active element,
14676  // i.e. concourse or non-station name at a blank element
14677  {
14678  ShowTrackFloatFlag = true;
14679  if(InactiveTrackElement.TrackType != Parapet)
14680  {
14681  if(IATrackSN == "")
14682  {
14683  TrackFloat = "Location unnamed\nID = " + AnsiString(InactiveTrackElement.ElementID);
14684  }
14685  else
14686  {
14687  TrackFloat = "Location = " + IATrackSN + '\n' + "ID = " + AnsiString(InactiveTrackElement.ElementID);
14688  }
14689  }
14690  else // it is a parapet, just show the ID
14691  {
14692  TrackFloat = "ID = " + AnsiString(InactiveTrackElement.ElementID);
14693  }
14694  }
14695  }
14696 // end of TrackFloat section
14697 
14698  bool OAListBoxFloatRequired = false; //identifies which window needs the float
14699  if(Level1Mode == OperMode && ((TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") || (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")))
14700  // if caption is 'Hide' label is required
14701  {
14702  bool FoundFlag;
14703  AnsiString FormatOneDPStr = "####0.0";
14704  AnsiString FormatNoDPStr = "#######0";
14705 // AnsiString Format5DPStr = "####0.00000"; //temporary
14706  AnsiString MaxBrakeStr = ""; // , EntrySpeedStr="", HalfStr="", FullStr="", MaxAtHalfStr="";//test
14707  AnsiString SpecialStr = "";
14708  if(OperatorActionPanel->Visible) //added after v2.6.1 to show floating window for trains in actions due list
14709  {
14710  if(OAListBox->MouseInClient && !OperatorActionPanel->MouseInClient && OAListBoxRightMouseButtonDown)
14711  {
14712  int X = OAListBox->ScreenToClient(MousePoint).x;
14713  int Y = OAListBox->ScreenToClient(MousePoint).y;
14714  int TrainID = -1, ContinuationPos = -1;
14715  if(GetTrainIDOrContinuationPosition(1, X, Y, TrainID, ContinuationPos))
14716  {
14717  OAListBoxFloatRequired = true;
14718  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
14719  {
14720  ShowTrainStatusFloatFlag = true;
14721  }
14722  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14723  {
14724  ShowTrainTTFloatFlag = true;
14725  }
14726  if((TrainID > -1) && (ShowTrainStatusFloatFlag || ShowTrainTTFloatFlag))
14727  {
14728  TTrain Train = TrainController->TrainVectorAtIdent(53, TrainID);
14729  TrainStatusFloat = GetTrainStatusFloat(0, TrainID, FormatNoDPStr, SpecialStr);
14730  TrainTTFloat = Train.FloatingTimetableString(1, Train.ActionVectorEntryPtr);
14731  }
14732  else if(ContinuationPos > -1)
14733  {
14734  GetTrainFloatingInfoFromContinuation(0, ContinuationPos, FormatNoDPStr, SpecialStr, TrainStatusFloat, TrainTTFloat);
14735  }
14736  }
14737  }
14738  }
14739 
14740 
14741  if(!OAListBoxFloatRequired) //condition added after v2.6.1 so only one floating window can show
14742  {
14743  int VecPos = Track->GetVectorPositionFromTrackMap(6, HLoc, VLoc, FoundFlag);
14744  if(FoundFlag && !MouseOverOAPanel) //MouseOverOAPanel added at v2.7.0 to prevent trains showimng behind OA panel
14745  {
14746  if(Track->TrackElementAt(450, VecPos).TrainIDOnElement > -1)
14747  // if a bridge & 2 trains at that position will select the train with TrainIDOnElement set
14748  {
14749  int TrainID = Track->TrackElementAt(452, VecPos).TrainIDOnElement;
14750  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
14751  {
14752  ShowTrainStatusFloatFlag = true;
14753  TrainStatusFloat = GetTrainStatusFloat(1, TrainID, FormatNoDPStr, SpecialStr);
14754  }
14755  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14756  {
14757  ShowTrainTTFloatFlag = true;
14758  TTrain Train = TrainController->TrainVectorAtIdent(54, TrainID);
14759  TrainTTFloat = Train.FloatingTimetableString(0, Train.ActionVectorEntryPtr);
14760  }
14761  }
14762 
14763  else if(Track->TrackElementAt(666, VecPos).TrackType == Continuation)
14764  // always give train information if a train present, but if not & either of train status or timetable info
14765  // selected then give next expected train to enter, or 'No trains expected'
14766  {
14767  TrainStatusFloat = "No trains expected";
14768  TrainTTFloat = "No timetable";
14769  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
14770  ShowTrainStatusFloatFlag = true;
14771  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14772  ShowTrainTTFloatFlag = true;
14774  {
14775  GetTrainFloatingInfoFromContinuation(1, VecPos, FormatNoDPStr, SpecialStr, TrainStatusFloat, TrainTTFloat);
14776  }
14777  }
14778  }
14779  }
14780  }
14781 
14782 // end of TrainFloat section
14783  AnsiString Caption;
14784 
14785  if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14786  {
14787  FloatingPanel->Visible = false;
14788  Utilities->CallLogPop(1485);
14789  return; // return with label invisible
14790  }
14791  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14792  {
14793  Caption = TrackFloat;
14794  }
14795  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14796  {
14797  Caption = TrainStatusFloat;
14798  }
14799  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14800  {
14801  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
14802  }
14803  else if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14804  {
14805  if(TrainStatusFloat == "No trains expected")
14806  Caption = TrainStatusFloat;
14807  else
14808  Caption = TrainTTFloat;
14809  }
14810  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14811  {
14812  if(TrainStatusFloat == "No trains expected")
14813  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
14814  else
14815  Caption = TrainTTFloat + '\n' + '\n' + TrackFloat;
14816  }
14817  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14818  {
14819  if(TrainStatusFloat == "No trains expected")
14820  Caption = TrainStatusFloat;
14821  else
14822  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat;
14823  }
14824  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14825  {
14826  if(TrainStatusFloat == "No trains expected")
14827  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
14828  else
14829  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat + '\n' + '\n' + TrackFloat;
14830  }
14831 
14832  int WindowOffsetLeft = 16;
14833  int WindowOffsetRight = 16;
14834  if(OAListBoxFloatRequired)
14835  {
14836  WindowOffsetLeft = 32;
14837  WindowOffsetRight = 64;
14838  }
14839 
14840  FloatingLabel->Caption = Caption; //set this here so dimensions correct in calculations, moved from below at v2.7.0
14841  FloatingPanel->Visible = true; //need this or dimensions still not valid, moved from below at v2.7.0
14842 
14843  int Left = ScreenX + MainScreen->Left + WindowOffsetRight; // so lhs of window is WindowOffset to the right of the mouse pos
14844 // this offset is because window position is relative to the interface form, whereas ScreenX & Y are relative to the MainScreen, which is
14845 // offset 32 to the right and 95 down from the interface form
14846  if((Left + FloatingPanel->Width) > MainScreen->Left + MainScreen->Width)
14847  Left = ScreenX - FloatingPanel->Width + 32 - WindowOffsetLeft; // so rhs of window is 32 - WindowOffset to the left of the mouse pos (+32 would be at mouse pos)
14848  int Top = ScreenY + MainScreen->Top + 16; // so top of window is one element below the mouse pos (ScreenY + MainScreen->Top would be at mouse pos)
14849 
14850  if((Top + FloatingPanel->Height) > MainScreen->Top + MainScreen->Height)
14851  {
14852  Top = ScreenY - FloatingPanel->Height + 79; // so bottom of window is one element above the mouse pos (95 would be at mouse pos)
14853  // but, top may now be off the top of the screen, if so position at the top of the screen, as always need to see the top, if have to
14854  // lose something then it's best to be from the bottom
14855  if(Top < 30) // use 30 instead of MainScreen->Top [95] as top can go off MainScreen providing it doesn't reach the information panel, as that would
14856  // obscure the window
14857  {
14858  Top = 30;
14859  }
14860  }
14861 /* if((Left != FloatingPanel->Left) || (Top != FloatingPanel->Top)) //dropped at v2.7.0 as causes more flickler than allowing window to move with mouse
14862  {
14863  FloatingPanel->Visible = false; // so doesn't flicker when reposition
14864  FloatingPanel->Left = Left;
14865  FloatingPanel->Top = Top;
14866  Utilities->CallLogPop(1917);
14867  return;
14868  }
14869 */
14870 
14871  FloatingPanel->Left = Left; //new at v2.7.0 in place of above
14872  FloatingPanel->Top = Top;
14873 
14874 // FloatingLabel->Caption = Caption; moved up at v2.7.0
14875 // FloatingPanel->Visible = true; // moved up at v2.7.0
14876  FloatingPanel->BringToFront();
14877  Utilities->CallLogPop(746);
14878 }
14879 
14880 // ---------------------------------------------------------------------------
14881 
14882 void TInterface::GetTrainFloatingInfoFromContinuation(int Caller, int VecPos, AnsiString FormatNoDPStr, AnsiString SpecialStr, AnsiString &TrainStatusFloat, AnsiString &TrainTTFloat)
14883 {
14884  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrainFloatingInfoFromContinuation");
14886  int LineSpeedLimit = Track->TrackElementAt(906, VecPos).SpeedLimit01; // speed only in 01 as a continuation
14887  float EntrySpeed;
14889  {
14890  while((CTEIt != TrainController->ContinuationTrainExpectationMultiMap.end()) && ((CTEIt->second.VectorPosition != VecPos) ||
14891  (CTEIt->second.TrainDataEntryPtr->TrainOperatingDataVector.at(CTEIt->second.RepeatNumber).RunningEntry != NotStarted)))
14892  {
14893  CTEIt++;
14894  }
14896  {
14897  TTrainDataEntry *TTDEPtr = CTEIt->second.TrainDataEntryPtr;
14898  AnsiString ServiceReferenceInfo = "";
14899  // Repeat information
14900  if(TTDEPtr->NumberOfTrains > 1) // Service reference information
14901  {
14902  if(CTEIt->second.RepeatNumber == 0)
14903  {
14904  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
14905  ServiceReferenceInfo = "\nFirst service of ref. " + TTDEPtr->ServiceReference;
14906  else
14907  ServiceReferenceInfo = "\nFirst service";
14908  }
14909  else if(CTEIt->second.HeadCode == TTDEPtr->ServiceReference)
14910  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber);
14911  else
14912  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber) + " of ref. " +
14913  TTDEPtr->ServiceReference;
14914  }
14915  else
14916  {
14917  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
14918  ServiceReferenceInfo = "\nService reference " + TTDEPtr->ServiceReference;
14919  }
14920  if(TTDEPtr->ActionVector.at(0).SignallerControl) // entry at 0 is the start entry
14921  {
14922  SpecialStr = "\nTrain under signaller control";
14923  EntrySpeed = TTDEPtr->SignallerSpeed;
14924  if(EntrySpeed > LineSpeedLimit)
14925  EntrySpeed = LineSpeedLimit;
14926  }
14927  else
14928  {
14929  EntrySpeed = TTDEPtr->StartSpeed;
14930  if(EntrySpeed > LineSpeedLimit)
14931  EntrySpeed = LineSpeedLimit;
14932  }
14933  if((CTEIt->first + TDateTime(1.0 / 1440)) < TrainController->TTClockTime) // has to be at least 1 min late to show as late
14934  {
14935  TDateTime TempTime = CTEIt->first;
14936 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
14937  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
14938  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nDelayed, was due at " +
14939  Utilities->Format96HHMM(TempTime);
14940  }
14941  else
14942  {
14943  TDateTime TempTime = CTEIt->first;
14944 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
14945  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
14946  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nExpected at " +
14947  Utilities->Format96HHMM(TempTime);
14948  }
14949  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14950  {
14951  if(!TTDEPtr->ActionVector.at(0).SignallerControl) // if signaller control there's no timetable & SpecialStr covers this
14952  {
14953  TrainTTFloat = TrainController->ContinuationEntryFloatingTTString(0, TTDEPtr, CTEIt->second.RepeatNumber,
14954  CTEIt->second.IncrementalMinutes, CTEIt->second.IncrementalDigits);
14955  }
14956  }
14957  }
14958  }
14959  Utilities->CallLogPop(2262);
14960 }
14961 
14962 // ---------------------------------------------------------------------------
14963 
14964 AnsiString TInterface::GetTrainStatusFloat(int Caller, int TrainID, AnsiString FormatNoDPStr, AnsiString SpecialStr) //new after v2.6.1 to make it easier to show also from actions due panel
14965 {
14966  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrainStatusFloat");
14967  AnsiString HeadCode = "", ServiceReferenceInfo = "", Status = "", CurrSpeedStr = "", BrakePCStr = "", NextStopStr = "", TimeLeftStr = "",
14968  TimeToNextMovementStr = "", MassStr = "", PowerStr = "";
14969  AnsiString FormatOneDPStr = "####0.0", MaxBrakeStr = "", MaxSpeedStr = "", TrainStatusFloat;
14970 
14971  double CurrSpeed;
14972  TTrain Train = TrainController->TrainVectorAtIdent(1, TrainID);
14973  MassStr = AnsiString::FormatFloat(FormatNoDPStr, ((double)Train.Mass) / 1000); // Te
14974  PowerStr = AnsiString::FormatFloat(FormatNoDPStr, Train.PowerAtRail / 1000 / 0.8); // kW
14975  if(Train.BeingCalledOn)
14976  MaxSpeedStr = "30";
14977  else
14978  MaxSpeedStr = AnsiString::FormatFloat(FormatNoDPStr, Train.MaxRunningSpeed);
14979  TDateTime ElapsedDeltaT = TrainController->TTClockTime - Train.EntryTime;
14980  TDateTime FirstHalfTimeDeltaT = Train.ExitTimeHalf - Train.EntryTime;
14981  TDateTime SecondHalfTimeDeltaT = Train.ExitTimeFull - Train.EntryTime - FirstHalfTimeDeltaT;
14982  TDateTime TimeLeft;
14983  double BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
14984  MaxBrakeStr = AnsiString::FormatFloat(FormatNoDPStr, (Train.MaxBrakeRate * Train.Mass / 9810));
14985  HeadCode = Train.HeadCode;
14986  if(Train.TrainDataEntryPtr->NumberOfTrains > 1) // Service reference information added at v0.6b
14987  {
14988  if(Train.RepeatNumber == 0)
14989  {
14990  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
14991  ServiceReferenceInfo = "\nFirst service of ref. " + Train.TrainDataEntryPtr->ServiceReference;
14992  else
14993  ServiceReferenceInfo = "\nFirst service";
14994  }
14995  else if(HeadCode == Train.TrainDataEntryPtr->ServiceReference)
14996  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber);
14997  else
14998  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber) + " of ref. " +
15000  }
15001  else
15002  {
15003  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
15004  ServiceReferenceInfo = "\nService reference " + Train.TrainDataEntryPtr->ServiceReference;
15005  }
15006  if(Train.Stopped())
15007  {
15008  if(Train.SignallerStopped)
15009  Status = "Stopped on signaller's instruction"; // if stopped for any other reason that will diplay
15010  if(Train.NotInService)
15011  Status = "Not in service"; // not used so far but leave it in
15012  if(Train.StoppedAtBuffers)
15013  Status = "Stopped at buffers";
15014  if(Train.StoppedAtSignal)
15015  Status = "Stopped at signal";
15016  if(Train.StoppedForTrainInFront)
15017  Status = "Stopped - forward track occupied"; // before station stop as want to display station stop if that set
15018  if(Train.StoppedAtLocation)
15019  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName;
15020  if((Train.StoppedAtLocation) && (Train.StoppedForTrainInFront))
15021  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName + " + forward track occupied";
15022  if(Train.StoppedWithoutPower)
15023  {
15024  if(Train.TrainFailed)
15025  Status = "Stopped without power - train failed";
15026  else
15027  Status = "Stopped without power";
15028  }
15029  if(Train.StoppedAfterSPAD)
15030  Status = "Stopped - signal passed at danger";
15031  if(Train.Derailed)
15032  Status = "Derailed";
15033  if(Train.Crashed)
15034  Status = "Crashed";
15035  CurrSpeed = 0;
15036  }
15037  else if(Train.OneLengthAccelDecel)
15038  {
15039  if(Train.FirstHalfMove)
15040  {
15041  Status = "Accelerating"; // just display a linear speed rise over half length
15042  BrakePCRate = 0; // reset to proper value during braking
15043  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
15044  }
15045  else
15046  {
15047  BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
15048  if(BrakePCRate < 55)
15049  Status = "Light braking";
15050  else if(BrakePCRate < 90)
15051  Status = "Heavy braking";
15052  else
15053  Status = "Emergency braking";
15054  CurrSpeed = Train.ExitSpeedHalf - 3.6 * (Train.BrakeRate * (TrainController->TTClockTime - Train.ExitTimeHalf) * 86400.0);
15055  }
15056  }
15057  else if(Train.BrakeRate > 0.01)
15058  {
15059  if(BrakePCRate < 55)
15060  Status = "Light braking";
15061  else if(BrakePCRate < 90)
15062  Status = "Heavy braking";
15063  else
15064  Status = "Emergency braking";
15065  CurrSpeed = Train.EntrySpeed - 3.6 * (Train.BrakeRate * ElapsedDeltaT * 86400.0);
15066  }
15067 
15068  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedHalf > (Train.EntrySpeed + 0.01)) && Train.FirstHalfMove)
15069  {
15070  Status = "Accelerating"; // just display a linear speed rise over half length
15071  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
15072  }
15073 
15074  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull > (Train.ExitSpeedHalf + 0.01)) && !Train.FirstHalfMove)
15075  {
15076  Status = "Accelerating";
15077  CurrSpeed = Train.ExitSpeedHalf +
15078  ((Train.ExitSpeedFull - Train.ExitSpeedHalf) * (double(ElapsedDeltaT - FirstHalfTimeDeltaT) / double(SecondHalfTimeDeltaT)));
15079  }
15080 
15081  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull <= Train.ExitSpeedHalf) && !Train.FirstHalfMove)
15082  {
15083  if(Train.PowerAtRail < 1)
15084  {
15085  if(Train.TrainFailed)
15086  {
15087  Status = "Coasting - train failed";
15088  }
15089  else
15090  {
15091  Status = "Coasting - no power";
15092  }
15093  CurrSpeed = Train.ExitSpeedFull;
15094  }
15095  else
15096  {
15097  Status = "Constant speed";
15098  CurrSpeed = Train.ExitSpeedFull;
15099  }
15100  }
15101 
15102  else // No braking, first half move, ExitSpeedHalf <= EntrySpeed
15103  {
15104  if(Train.PowerAtRail < 1) // as designed there is no way a vehicle can coast without having failed
15105  {
15106  if(Train.TrainFailed)
15107  {
15108  Status = "Coasting - train failed";
15109  }
15110  else
15111  {
15112  Status = "Coasting - no power";
15113  }
15114  CurrSpeed = Train.ExitSpeedHalf;
15115  }
15116  else
15117  {
15118  Status = "Constant speed";
15119  CurrSpeed = Train.ExitSpeedHalf;
15120  }
15121  }
15122  if(Train.TimetableFinished)
15123  {
15124  if(Train.TrainMode == Signaller)
15125  NextStopStr = "At signaller's discretion";
15126  else
15127  NextStopStr = "None";
15128  }
15129  else
15130  NextStopStr = Train.FloatingLabelNextString(0, Train.ActionVectorEntryPtr);
15131  if(Train.TrainMode == Signaller)
15132  {
15133  SpecialStr = "Train under signaller control" + AnsiString('\n');
15134  }
15135  else if(Train.BeingCalledOn && !Train.StoppedAtLocation)
15136  {
15137  SpecialStr = "Restricted speed - being called on" + AnsiString('\n');
15138  }
15139 
15140  double RemTimeHalf = 86400.0 * double(Train.ExitTimeHalf - TrainController->TTClockTime);
15141  if(RemTimeHalf < 0)
15142  RemTimeHalf = 0;
15143  double RemTimeFull = 86400.0 * double(Train.ExitTimeFull - TrainController->TTClockTime);
15144  if(RemTimeFull < 0)
15145  RemTimeFull = 0;
15146  if(RemTimeHalf > 0)
15147  TimeLeft = RemTimeHalf;
15148  else
15149  TimeLeft = RemTimeFull;
15150  TimeToNextMovementStr = "Time to next movement (sec) = " + TimeLeftStr.FormatFloat(FormatOneDPStr, TimeLeft);
15151  if(Train.Stopped())
15152  TimeToNextMovementStr = "";
15153  if(Train.Stopped())
15154  {
15155  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " +
15156  MaxSpeedStr + "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr +
15157  Status + '\n' + "Next: " + NextStopStr;
15158  }
15159  else
15160  {
15161  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " +
15162  MaxSpeedStr + "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr +
15163  Status + ": " + CurrSpeedStr.FormatFloat(FormatNoDPStr, CurrSpeed) + "km/h" + '\n' + "Next: " + NextStopStr;
15164  }
15165  Utilities->CallLogPop(2263);
15166  return TrainStatusFloat;
15167 }
15168 
15169 // ---------------------------------------------------------------------------
15170 
15171 void TInterface::FlashingGraphics(int Caller, TDateTime Now)
15172  // following section checks to see if GapFlashFlag set & flashes the Gap graphics if so
15173  // Gap flashing is cancelled on any mousedown event
15174 
15175  // deal with flashing GapFlash graphics (only in basic mode so no need to check for trains)
15176 {
15177  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FlashingGraphics");
15179  {
15180  if(WarningFlash)
15181  {
15182  Track->GapFlashGreen->PlotOverlay(4, Display); // only plotted if PlotOverlay reset
15184  }
15185  else
15186  {
15187  Track->GapFlashGreen->PlotOriginal(17, Display); // only plotted if PlotOverlay set
15189  }
15190  }
15191 
15193  {
15194  if(WarningFlash)
15195  {
15200  Display->Update();
15201  }
15202  else
15203  {
15208  Display->Update();
15209  }
15210  }
15211 
15212 //deal with gap setting - added at v2.6.1 to make location easier
15214  {
15216  }
15218  {
15219  Display->Ellipse(2, Track->GetGapHLoc() * 16, Track->GetGapVLoc() * 16, clB0G0R5);
15220  }
15221 
15223  {
15225  }
15227  {
15228  Display->Ellipse(3, Track->GetGapHLoc() * 16, Track->GetGapVLoc() * 16, clB5G5R5);
15229  }
15230 
15231 // deal with other flashing graphics
15233  {
15234  if((Now - RouteFlashStartTime) < TDateTime(RouteFlashDuration / 86400))
15235  {
15236  // cancel if train is moving & arrives on any part of flashing route
15238  {
15239  Track->RouteFlashFlag = false;
15241  ClearandRebuildRailway(18); // because using ConstructRoute->RouteFlash.PlotOriginal() can plot wrong point fillet as well as
15242  // original (if proposed route would change point). With this can dispense with ConstructRoute->RouteFlash.PlotOriginal()
15243  Utilities->CallLogPop(75);
15244  return;
15245  }
15246 
15247  InfoPanel->Visible = true;
15248  if(Level2OperMode == PreStart)
15249  InfoPanel->Caption = "PRE-START: Route setting in progress";
15250  else
15251  InfoPanel->Caption = "OPERATING: Route setting in progress";
15252  if(WarningFlash)
15253  {
15255  }
15256  else
15257  {
15259  }
15260  }
15261  else
15262  {
15263 // ConstructRoute->RouteFlash.PlotOriginal(); don't need with clearand....
15264 // stop clock while converting route as can take several seconds
15265  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
15267  if(PreferredRouteFlag)
15269  else
15271  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
15272  TrainController->BaseTime = TDateTime::CurrentDateTime();
15274  Track->RouteFlashFlag = false;
15276  ClearandRebuildRailway(19); // if drop this ensure replot trains after replot routes else route will overwrite a train
15277  }
15278  }
15279 
15280  if(Track->RouteFlashFlag && Display->ZoomOutFlag) // must have entered RouteFlash from normal screen so button states stored
15281  // dropped ZoomOutButton when route or point flashing, but leave this section in in case need to reinstate
15282  // no need to call Clearand... as that is called when revert to normal mode
15283  {
15284  if((Now - RouteFlashStartTime) >= TDateTime(RouteFlashDuration / 86400))
15285  {
15286  Track->RouteFlashFlag = false;
15287  if(PreferredRouteFlag)
15288  {
15290  }
15291  else
15292  {
15294  }
15295  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
15296  }
15297  }
15298 
15300  {
15301  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
15302  {
15303  // cancel if train is present on or enters a flashing point, either selected or diverging
15305  {
15307  Track->PointFlashFlag = false;
15309  Utilities->CallLogPop(76);
15310  return;
15311  }
15313  {
15315  Track->PointFlashFlag = false;
15317  Utilities->CallLogPop(77);
15318  return;
15319  }
15320 
15321  if(WarningFlash)
15322  {
15325  }
15326  else
15327  {
15329  }
15330  }
15331  else
15332  {
15337  {
15341  }
15343  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
15344  Track->PointFlashFlag = false;
15346  }
15347  }
15348 
15350  // dropped ZoomOutButton when point flashing but leave this section in in case need to reinstate
15351  {
15352  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
15353  {
15357  {
15360  }
15361  Track->PointFlashFlag = false;
15363  }
15364  }
15365 // deal with level crossings
15366  if(!Track->ChangingLCVector.empty() && (Level2OperMode != Paused))
15367  {
15368  int H;
15369  int V;
15370 
15371  for(unsigned int x = 0; x < Track->ChangingLCVector.size(); x++)
15372  {
15373  bool Manual = false;
15374  if(Track->ChangingLCVector.at(x).TypeOfRoute == 2) //manual
15375  {
15376  Manual = true;
15377  }
15378  H = Track->ChangingLCVector.at(x).HLoc;
15379  V = Track->ChangingLCVector.at(x).VLoc;
15380  if((Now - Track->ChangingLCVector.at(x).StartTime) < TDateTime((Track->ChangingLCVector.at(x).ChangeDuration) / 86400))
15381  // still flashing
15382  {
15383  if(WarningFlash)
15384  {
15385  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising) // closing to trains
15386  {
15387  Track->PlotRaisedLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display); //always plots red when raising
15388  }
15389  else
15390  {
15391  Track->PlotLoweredLinkedLevelCrossingBarriers(0, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
15392  Track->ChangingLCVector.at(x).TypeOfRoute, Display, Manual);
15393  }
15394  }
15395  else
15396  {
15397  Track->PlotLCBaseElementsOnly(2, Track->ChangingLCVector.at(x).BarrierState, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
15398  Track->ChangingLCVector.at(x).TypeOfRoute, Display);
15399  }
15400  }
15401  else
15402  // flashing period finished
15403  {
15404  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising)
15405  {
15406  Track->PlotRaisedLinkedLevelCrossingBarriers(2, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display); //always plot red when fully raised
15407  Track->SetLinkedLevelCrossingBarrierAttributes(4, H, V, 0); // only set attr to 0 when fully raised
15408  // attributes set to 2 when changing state, now reset to 0, no other actions needed
15409  }
15410  else
15411  // barriers lowering
15412  {
15413  Track->PlotLoweredLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
15414  Track->ChangingLCVector.at(x).TypeOfRoute, Display, Manual);
15415  Track->SetLinkedLevelCrossingBarrierAttributes(5, H, V, 1); // only set attr to 1 when fully lowered
15416  bool FoundFlag;
15417  int TVPos = Track->GetVectorPositionFromTrackMap(46, H, V, FoundFlag);
15418  if(!FoundFlag)
15419  {
15420  throw Exception("Failed to find a route at LC position HLoc = " + (AnsiString)H + " VLoc = " + (AnsiString)V);
15421  }
15422  int RouteNumber;
15423  AllRoutes->GetRouteTypeAndNumber(24, TVPos, 0, RouteNumber); // use 0 for LinkPos, could be 1 or 0 as only a single track element
15424  // don't need returned value of RouteType
15425  if(RouteNumber > -1) // if train crashed then there won't be a routenumber
15426  {
15427  AllRoutes->GetFixedRouteAt(196, RouteNumber).SetRouteSignals(8);
15428  }
15429  }
15430  }
15431  }
15432  for(int x = Track->ChangingLCVector.size() - 1; x >= 0; x--)
15433  // now transfer lowering barrier object from the ChangingLCVector to the BarriersDownVector if lowering, reset the start timer (to time the barrier down period)
15434  // and for either raising or lowering erase the object from the ChangingLCVector
15435  {
15436  if(!Track->IsLCBarrierFlashingAtHV(0, Track->ChangingLCVector.at(x).HLoc, Track->ChangingLCVector.at(x).VLoc))
15437  {
15438  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Lowering)
15439  {
15440  Track->ChangingLCVector.at(x).StartTime = TrainController->TTClockTime;
15441  Track->ChangingLCVector.at(x).BarrierState = TTrack::Down;
15442  Track->BarriersDownVector.push_back(Track->ChangingLCVector.at(x));
15443  }
15444  Track->ChangingLCVector.erase(Track->ChangingLCVector.begin() + x);
15445  }
15446  }
15447  }
15448  Utilities->CallLogPop(747);
15449 }
15450 
15451 // ---------------------------------------------------------------------------
15452 
15454  // set boundary, Home, NewHome, ZoomOut, CallingOn buttons & menu items as appropriate
15455 {
15456  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetSaveMenuAndButtons");
15457 
15458 // set save railway buttons
15459  bool SaveRailwayButtonsFlag = true;
15460 
15461  SaveRailwayTBPButton->Visible = true;
15462  SaveRailwayPDPButton->Visible = true;
15463  SaveSessionButton->Visible = true;
15464  if(Level1Mode == OperMode)
15465  {
15467  {
15468  SaveRailwayButtonsFlag = false;
15469  }
15470  // set PresetAutoSigRoutesButton enabled or not
15471  // enable if PreStart & no routes set
15472  if((Level2OperMode == PreStart) && (AllRoutes->AllRoutesVector.empty()))
15473  {
15474  PresetAutoSigRoutesButton->Enabled = true;
15475  }
15476  else
15477  {
15478  PresetAutoSigRoutesButton->Enabled = false;
15479  }
15480  }
15481  else
15482  {
15484  {
15485  SaveRailwayButtonsFlag = false;
15486  }
15487  else if(SavedFileName != "")
15488  {
15489  if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
15490  {
15491  if(!(Track->IsReadyForOperation(false)))
15492  {
15493  SaveRailwayButtonsFlag = false; // can't save under its old name as not now a .rly file
15494  }
15495  }
15496  }
15497  }
15498  if(SaveRailwayButtonsFlag && (Level1Mode == BaseMode))
15499  {
15500  SaveRailwayBaseModeButton->Visible = true;
15501  }
15502  else
15503  {
15504  SaveRailwayBaseModeButton->Visible = false;
15505  }
15506  SaveRailwayTBPButton->Enabled = SaveRailwayButtonsFlag;
15507  SaveRailwayPDPButton->Enabled = SaveRailwayButtonsFlag;
15508  SaveRailwayBaseModeButton->Enabled = SaveRailwayButtonsFlag;
15509  SaveSessionButton->Enabled = SaveRailwayButtonsFlag;
15510 
15511 // set formatted timetable menu item
15512  if(TimetableTitle == "")
15513  {
15514  ExportTTMenuItem->Enabled = false;
15515  }
15516  else
15517  {
15518  ExportTTMenuItem->Enabled = true;
15519  }
15520 
15521 // set info menu items
15523  {
15524  FloatingInfoMenu->Enabled = false;
15525  TrackInfoMenuItem->Enabled = false;
15526  TrainInfoMenuItem->Enabled = false;
15527  }
15528  else
15529  {
15530  FloatingInfoMenu->Enabled = true;
15531  TrackInfoMenuItem->Enabled = true;
15532  if(Level1Mode == OperMode)
15533  {
15534  TrainInfoMenuItem->Enabled = true;
15535  }
15536  else
15537  {
15538  TrainInfoMenuItem->Enabled = false;
15539  }
15540  }
15541 
15542 // set all bar CallingOnButton operational to begin with - no, causes flickering of button graphics,
15543 // work on internal flags & then set buttons according to final flag values, then graphic won't change unless
15544 // there has been a legitimate change of state since the last access
15545 
15546  bool ZoomFlag = true, HomeFlag = true, NewHomeFlag = true, ScreenLeftFlag = true, ScreenRightFlag = true, ScreenUpFlag = true, ScreenDownFlag = true,
15547  TrackBuildPanelEnabledFlag = true, PrefDirPanelEnabledFlag = true, OperatingPanelEnabledFlag = true, TimetablePanelEnabledFlag = true;
15548 
15549  AnsiString TrackBuildPanelLabelCaptionStr = "Build/modify";
15550  AnsiString PrefDirPanelLabelCaptionStr = "Preferred direction selection";
15551  AnsiString OperatingPanelLabelCaptionStr = "Operation";
15552  AnsiString TimetablePanelLabelCaptionStr = "Timetable editor";
15553 
15554  if(!Display->ZoomOutFlag)
15555  { // prevent if half a screen or less visible (width = 60, height = 36) [Note HLocMin & Max 1 greater than extreme element]
15557  ScreenLeftFlag = false; // 60 - 30
15559  ScreenRightFlag = false; // 60 - (60 - 30)
15561  ScreenUpFlag = false; // 36 - 18
15563  ScreenDownFlag = false; // 36 - (36 - 18)
15564  }
15565  else
15566  { // prevent if less than a quarter of a screen visible (width = 240, height = 144)
15568  ScreenLeftFlag = false; // 240 - 60
15570  ScreenRightFlag = false; // 240 - (240 - 60)
15572  ScreenUpFlag = false; // 144 - 36
15574  ScreenDownFlag = false; // 144 - (144 - 36)
15575  }
15577  {
15578  ZoomFlag = false;
15579  HomeFlag = false;
15580  NewHomeFlag = false;
15581  ScreenLeftFlag = false;
15582  ScreenRightFlag = false;
15583  ScreenUpFlag = false;
15584  ScreenDownFlag = false;
15585  }
15586 
15587  if(Display->ZoomOutFlag)
15588  {
15589 // NewHomeFlag = false;
15590  TrackBuildPanelEnabledFlag = false;
15591  TrackBuildPanelLabelCaptionStr = "Disabled";
15592  PrefDirPanelEnabledFlag = false;
15593  PrefDirPanelLabelCaptionStr = "Disabled";
15594  OperatingPanelEnabledFlag = false;
15595  OperatingPanelLabelCaptionStr = "Disabled";
15596  TimetablePanelEnabledFlag = false;
15597  TimetablePanelLabelCaptionStr = "Disabled";
15598  }
15599 
15600  if(Level1Mode == OperMode)
15601  {
15602  if(Track->RouteFlashFlag || Track->PointFlashFlag || TTClockAdjPanel->Visible == true || TTClockAdjustWarningPanel->Visible == true) //TTClockAdjPanel added for v2.4.2 to keep it disabled after Clock2Stopped dropped
15603  {
15604  MTBFEditBox->Enabled = false;
15605  OperatingPanelEnabledFlag = false;
15606  OperatingPanelLabelCaptionStr = "Disabled";
15607  ZoomFlag = false;
15608  HomeFlag = false;
15609  NewHomeFlag = false;
15610  ScreenLeftFlag = false;
15611  ScreenRightFlag = false;
15612  ScreenUpFlag = false;
15613  ScreenDownFlag = false;
15614  SaveOperatingImageMenuItem->Enabled = false;
15615  }
15616  else
15617  {
15618  MTBFEditBox->Enabled = true;
15619  SaveOperatingImageMenuItem->Enabled = true;
15620  }
15621  }
15622 
15623  if(LocationNameTextBox->Visible)
15624  {
15625  ZoomFlag = false;
15626  HomeFlag = false;
15627  NewHomeFlag = false;
15628  ScreenLeftFlag = false;
15629  ScreenRightFlag = false;
15630  ScreenUpFlag = false;
15631  ScreenDownFlag = false;
15632  }
15633 
15634  if(TextBox->Visible) // added at v1.3.0 to prevent screen moving when movement keys pressed during text entry
15635  {
15636  ZoomFlag = false;
15637  HomeFlag = false;
15638  NewHomeFlag = false;
15639  ScreenLeftFlag = false;
15640  ScreenRightFlag = false;
15641  ScreenUpFlag = false;
15642  ScreenDownFlag = false;
15643  }
15644 
15645  if((Level1Mode == TimetableMode) && (TimetableEditPanel->Visible))
15646  // added at v1.3.0 to prevent screen moving when movement keys pressed during timetable compilation (allowed if TT hidden)
15647  {
15648  ZoomFlag = false;
15649  HomeFlag = false;
15650  NewHomeFlag = false;
15651  ScreenLeftFlag = false;
15652  ScreenRightFlag = false;
15653  ScreenUpFlag = false;
15654  ScreenDownFlag = false;
15655  }
15656 
15659  {
15660  ZoomFlag = false;
15661  }
15662 
15663  if(ZoomFlag)
15664  ZoomButton->Enabled = true;
15665  else
15666  ZoomButton->Enabled = false;
15667  if(HomeFlag)
15668  HomeButton->Enabled = true;
15669  else
15670  HomeButton->Enabled = false;
15671  if(NewHomeFlag)
15672  NewHomeButton->Enabled = true;
15673  else
15674  NewHomeButton->Enabled = false;
15675  if(ScreenLeftFlag)
15676  ScreenLeftButton->Enabled = true;
15677  else
15678  ScreenLeftButton->Enabled = false;
15679  if(ScreenRightFlag)
15680  ScreenRightButton->Enabled = true;
15681  else
15682  ScreenRightButton->Enabled = false;
15683  if(ScreenUpFlag)
15684  ScreenUpButton->Enabled = true;
15685  else
15686  ScreenUpButton->Enabled = false;
15687  if(ScreenDownFlag)
15688  ScreenDownButton->Enabled = true;
15689  else
15690  ScreenDownButton->Enabled = false;
15691  if(OperatingPanelEnabledFlag)
15692  OperatingPanel->Enabled = true;
15693  else
15694  OperatingPanel->Enabled = false;
15695  if(TrackBuildPanelEnabledFlag)
15696  TrackBuildPanel->Enabled = true;
15697  else
15698  TrackBuildPanel->Enabled = false;
15699  if(PrefDirPanelEnabledFlag)
15700  PrefDirPanel->Enabled = true;
15701  else
15702  PrefDirPanel->Enabled = false;
15703  if(TimetablePanelEnabledFlag)
15704  TimetablePanel->Enabled = true;
15705  else
15706  TimetablePanel->Enabled = false;
15707  TrackBuildPanelLabel->Caption = TrackBuildPanelLabelCaptionStr;
15708  PrefDirPanelLabel->Caption = PrefDirPanelLabelCaptionStr;
15709  OperatingPanelLabel->Caption = OperatingPanelLabelCaptionStr;
15710  TimetablePanelLabel->Caption = TimetablePanelLabelCaptionStr;
15711 
15712 // check if any CallingOnFlags set & set button accordingly
15713  if(Display->ZoomOutFlag)
15714  {
15715  CallingOnButton->Enabled = false;
15716  CallingOnButton->Down = false;
15717  }
15718  else
15719  {
15720  if(Level2OperMode == Operating)
15721  {
15722  bool CallOnValid = false;
15723  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
15724  {
15726  {
15727  CallingOnButton->Enabled = true;
15728  CallOnValid = true;
15729  }
15730  }
15731  if(!CallOnValid)
15732  {
15733  CallingOnButton->Enabled = false;
15734  CallingOnButton->Down = false;
15735  }
15736  }
15737  else
15738  {
15739  CallingOnButton->Enabled = false;
15740  CallingOnButton->Down = false;
15741  }
15742  }
15743  Utilities->CallLogPop(970);
15744 }
15745 
15746 // ---------------------------------------------------------------------------
15747 
15748 void TInterface::ErrorLog(int Caller, AnsiString Message)
15749 {
15750 // create an error file for diagnostic purposes called on detection of a runtime error
15751 
15752 // Note: For faults in ClockTimer2, after the catch block in ClockTimer2 which calls this function, execution continues from where
15753 // ClockTimer2 was called, so the Utilities->Clock2Stopped flag is cleared and the whole sequence repeats itself, including the fault, until
15754 // the user presses the Exit button. Note also that Utilities->CallLogPop, called when ClockTimer (not ClockTimer2) returns, pops the error
15755 // message off the back of the Utilities->CallLog, not the ClockTimer call. Hence entries keep stacking up, including the push_front entry
15756 // but not the push_back error entry, and when finally printed there is a whole series of entries for the one fault, the number
15757 // depending on the time taken to press Exit.
15758 // Hence introduce an ErrorLogCalledFlag, set to true on first call, and preventing further calls thereafter.
15759 
15760  if(ErrorLogCalledFlag)
15761  return;
15762 
15763  ErrorLogCalledFlag = true;
15764  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + "," + Message);
15765  Utilities->CallLog.push_front("Version: " + ProgramVersion + "; Time and date: " + Utilities->DateTimeStamp());
15766  SaveErrorFile();
15767  if((TempTTFileName != "") && FileExists(TempTTFileName))
15768  {
15769  DeleteFile(TempTTFileName);
15770  }
15771  Display->GetImage()->Visible = false;
15772  PerformancePanel->Visible = false;
15773  OperatorActionPanel->Visible = false; // new v2.2.0
15774  TrackBuildPanel->Visible = false;
15775  TrackElementPanel->Visible = false;
15776  LocationNameTextBox->Visible = false;
15777  TextBox->Visible = false;
15778  TrackLengthPanel->Visible = false;
15779  InfoPanel->Visible = false;
15780  PrefDirPanel->Visible = false;
15781  TimetablePanel->Visible = false;
15782  TimetableEditPanel->Visible = false;
15783  TrainController->TTEditPanelVisible = false; //added at v2.6.0 for two location message
15784  OperatingPanel->Visible = false;
15785  FloatingPanel->Visible = false;
15786  ModeMenu->Enabled = false;
15787  SigImagePanel->Visible = false; // new at v2.3.0
15788  FileMenu->Enabled = false;
15789  EditMenu->Enabled = false;
15790  FloatingInfoMenu->Enabled = false;
15791  HelpMenu->Enabled = false;
15792 // SaveHeaderMenu1->Enabled = false;
15793  ScreenLeftButton->Visible = false;
15794  ScreenRightButton->Visible = false;
15795  ScreenUpButton->Visible = false;
15796  ScreenDownButton->Visible = false;
15797  HomeButton->Visible = false;
15798  NewHomeButton->Visible = false;
15799  ZoomButton->Visible = false;
15800  PrefDirKey->Visible = false;
15801  DistanceKey->Visible = false;
15802  OutputLog1->Caption = "";
15803  OutputLog2->Caption = "";
15804  OutputLog3->Caption = "";
15805  OutputLog4->Caption = "";
15806  OutputLog5->Caption = "";
15807  OutputLog6->Caption = "";
15808  OutputLog7->Caption = "";
15809  OutputLog8->Caption = "";
15810  OutputLog9->Caption = "";
15811  OutputLog10->Caption = "";
15812  if(Caller == 113)
15813  {
15814  ErrorMessageStoreImage->Visible = true;
15815  }
15816  else
15817  {
15818  ErrorMessage->Visible = true;
15819  }
15820  ErrorButton->Visible = true;
15821  Screen->Cursor = TCursor(-2); // Arrow; - in case was an hourglass
15822 // No need for Utilities->CallLogPop as the call log deque has already been written to file & the next action
15823 // is to close the program when the exit button is pressed
15824 }
15825 
15826 // ---------------------------------------------------------------------------
15827 
15829  // not used from v2.2.0 as now allow floating panel & label to overlie performance panel
15830 {
15831  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPerformancePanelObscuringFloatingLabel");
15832  if(FloatingPanel->Visible == false)
15833  {
15834  Utilities->CallLogPop(1205);
15835  return false;
15836  }
15837 // pptop >= flbot, ppbot <= fltop, ppleft >= flright, ppright <= flleft
15838  if((PerformancePanel->Top >= (FloatingPanel->Top + FloatingPanel->Height)) || ((PerformancePanel->Top + PerformancePanel->Height) <= FloatingPanel->Top) ||
15839  (PerformancePanel->Left >= (FloatingPanel->Left + FloatingPanel->Width)) || ((PerformancePanel->Left + PerformancePanel->Width) <= FloatingPanel->Left))
15840  {
15841  Utilities->CallLogPop(1206);
15842  return false;
15843  }
15844  else
15845  {
15846  Utilities->CallLogPop(1207);
15847  return true;
15848  }
15849 }
15850 // ---------------------------------------------------------------------------
15851 
15852 void TInterface::SetCaption(int Caller)
15853 {
15854 /*
15855  NamedRailway; RlyFile; NamedTimetable
15856  n x x "New railway under development";
15857  y n x RailwayTitle + ": under development";
15858  y y n RailwayTitle + ": no timetable loaded";
15859  y y y RailwayTitle + ", " + TimetableTitle;
15860 */
15861 
15862  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetCaption");
15863  if(RailwayTitle == "")
15864  Caption = "Railway: New railway under development";
15865  else if(!RlyFile)
15866  Caption = "Railway: " + RailwayTitle + " under development";
15867 // else if(TimetableTitle == "") Caption = "Railway: " + RailwayTitle + "; Timetable: none loaded";
15868  else if(TimetableTitle == "")
15869  Caption = "Railway: " + RailwayTitle; // changed at v2.1.0, no need to mention TT if none loaded
15870  else
15871  Caption = "Railway: " + RailwayTitle + "; Timetable: " + TimetableTitle;
15872  Utilities->CallLogPop(1208);
15873 }
15874 
15875 // ---------------------------------------------------------------------------
15876 
15877 void TInterface::ResetAll(int Caller)
15878 {
15879  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAll");
15880  LastNonCtrlOrShiftKeyDown = -1; // added at v2.4.2 to no key down
15882  Track->GapFlashRedPosition = -1;
15883  Track->GapFlashFlag = false;
15884  Track->RouteFlashFlag = false;
15885  Track->PointFlashFlag = false;
15887  AutoSigsFlag = false;
15888  PreventGapOffsetResetting = false;
15889 
15890  Utilities->Clock2Stopped = false;
15891  TTClockSpeed = 1;
15892  TTClockSpeedLabel->Caption = "x1";
15893  Track->SetTrackFinished(false);
15895  CurrentSpeedButton = 0; // not assigned yet
15897  StartX = 0;
15898  StartY = 0;
15899  mbLeftDown = false;
15901  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
15903  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
15905  WarningFlashCount = 0;
15906 
15907  Level1Mode = BaseMode;
15908  SetLevel1Mode(26);
15909  RouteMode = None;
15910  PreferredRoute = true; //default starting conditions
15911  ConsecSignalsRoute = true; //default starting conditions
15912  DevelopmentPanel->Visible = false;
15913 
15914  MainScreen->Canvas->CopyMode = cmSrcCopy;
15915  FloatingPanel->Visible = false;
15916  OverallDistance = 0;
15917  OverallSpeedLimit = -1;
15918  AllRoutes->RouteTruncateFlag = false;
15919  CallingOnButton->Down = false;
15920  Display->ZoomOutFlag = false;
15921  ScreenGridFlag = false;
15922  InfoCaptionStore = "";
15923  ErrorLogCalledFlag = false;
15924  ErrorMessage->Visible = false;
15925  ErrorMessageStoreImage->Visible = false;
15926  TempCursorSet = false;
15927  TempCursor = TCursor(-2); // Arrow
15928  WholeRailwayMoving = false; // new at v2.1.0
15929 
15930  TrainController->TTClockTime = TDateTime(0); // default setting
15931  TTClockAdjPanel->Visible = false;
15933  ConflictPanel->Visible = false;
15934  SelectedTrainID = -1;
15935  SetTrackBuildImages(11);
15936 // TrackInfoOnOffMenuItem->Caption = "Show"; dropped these here at v1.2.0 so don't reset when load a session file
15937 // TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
15938 // TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
15939  Track->CalcHLocMinEtc(8);
15940  FileChangedFlag = false;
15941  RlyFile = false;
15942  SaveSessionFlag = false;
15943  LoadSessionFlag = false;
15944  SelectionValid = false;
15945  TimetableChangedFlag = false;
15946  SavedFileName = "";
15947  RailwayTitle = "";
15948  TimetableTitle = "";
15949  SetCaption(1);
15950  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
15951  // added for Beta v0.2b
15952  CreateEditTTTitle = ""; // as above
15953  AllRoutes->NextRouteID = 0;
15954  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
15955  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
15956 
15957  TempFont->Style.Clear();
15958  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
15959  TempFont->Size = 10;
15960  TempFont->Color = clB0G0R0;
15961  TempFont->Charset = (TFontCharset)(0);
15962  MainScreen->Canvas->Font->Assign(TempFont);
15963  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
15964  PerformancePanel->Left = MainScreen->Left;
15965  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new v2.2.0
15966  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width; ; // new v2.2.0
15967  // ScreenRightButton->Left = MainScreen->Width + MainScreen->Left; //Button values changed at v2.1.0 to allow for screen resizing
15968  // ScreenLeftButton->Left = ScreenRightButton->Left;
15969  // ScreenUpButton->Left = ScreenRightButton->Left;
15970  // ScreenDownButton->Left = ScreenRightButton->Left;
15971  // HomeButton->Left = ScreenRightButton->Left;
15972  // NewHomeButton->Left = ScreenRightButton->Left;
15973  // ZoomButton->Left = ScreenRightButton->Left;
15974  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height;
15975  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width; ; // new v2.2.0
15976 
15977  delete TempFont;
15978  CtrlKey = false;
15979  ShiftKey = false;
15980  Utilities->CallLogPop(1209);
15981 }
15982 
15983 // ---------------------------------------------------------------------------
15984 
15986 {
15987  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrackBuildImages,");
15988  if((Level1Mode == OperMode) || RlyFile)
15989  {
15990  TrackLinkedImage->Visible = false;
15991  TrackNotLinkedImage->Visible = false;
15992  GapsSetImage->Visible = false;
15993  GapsNotSetImage->Visible = false;
15994  LocationNamesSetImage->Visible = false;
15995  LocationNamesNotSetImage->Visible = false;
15996  Utilities->CallLogPop(1114);
15997  return;
15998  }
15999  else
16000  {
16001  if(!Track->NoActiveTrack(9))
16002  {
16003  if(Track->IsTrackFinished())
16004  {
16005  TrackLinkedImage->Visible = true;
16006  TrackNotLinkedImage->Visible = false;
16007  }
16008  else
16009  {
16010  TrackNotLinkedImage->Visible = true;
16011  TrackLinkedImage->Visible = false;
16012  }
16013  }
16014  else
16015  {
16016  TrackLinkedImage->Visible = false;
16017  TrackNotLinkedImage->Visible = false;
16018  }
16019 
16020  if(!Track->NoGaps(1))
16021  {
16022  if(Track->GapsUnset(6))
16023  {
16024  GapsNotSetImage->Visible = true;
16025  GapsSetImage->Visible = false;
16026  }
16027  else
16028  {
16029  GapsNotSetImage->Visible = false;
16030  GapsSetImage->Visible = true;
16031  }
16032  }
16033  else
16034  {
16035  GapsNotSetImage->Visible = false;
16036  GapsSetImage->Visible = false;
16037  }
16038 
16040  {
16041  if(Track->LocationsNotNamed(0))
16042  {
16043  LocationNamesSetImage->Visible = false;
16044  LocationNamesNotSetImage->Visible = true;
16045  }
16046  else
16047  {
16048  LocationNamesSetImage->Visible = true;
16049  LocationNamesNotSetImage->Visible = false;
16050  }
16051  }
16052  else
16053  {
16054  LocationNamesSetImage->Visible = false;
16055  LocationNamesNotSetImage->Visible = false;
16056  }
16057  }
16058  Utilities->CallLogPop(1113);
16059 }
16060 
16061 // ---------------------------------------------------------------------------
16062 
16063 void TInterface::ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
16064 {
16065  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetChangedFileDataAndCaption");
16066  FileChangedFlag = true;
16067  if(NonPrefDirChangesMade)
16068  {
16069  if(RlyFile) // i.e. was a Railway file but major changes made so class as a new railway
16070  {
16071  RailwayTitle = "";
16072  TimetableTitle = "";
16073  SavedFileName = "";
16074  RlyFile = false;
16075  }
16076  TimetableTitle = ""; // should have been reset already during user mode change but include here also
16077  SetTrackBuildImages(15);
16078  }
16079  SetCaption(2);
16080  Utilities->CallLogPop(1210);
16081 }
16082 
16083 // ---------------------------------------------------------------------------
16084 
16085 void TInterface::SaveSession(int Caller)
16086 { // ExcessLCDownMins saved as string after ***Interface*** see below
16087  try
16088  {
16089  TrainController->LogEvent("SaveSession");
16090  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSession");
16091  AnsiString CurrentDateTimeStr = "", TimetableTimeStr = "", SessionFileStr = "";
16092  Screen->Cursor = TCursor(-11); // Hourglass;
16093  CurrentDateTimeStr = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
16094  // avoid characters in filename:= / \ : * ? " < > |
16095  TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
16096  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
16097 // SessionFileStr = CurDir + "\\" + SESSION_DIR_NAME + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
16098 // "; " + TimetableTitle + ".ssn";
16099  SessionFileStr = LoadSessionDialog->InitialDir + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
16100  "; " + TimetableTitle + ".ssn";
16101  std::ofstream SessionFile(SessionFileStr.c_str());
16102  if(!(SessionFile.fail()))
16103  {
16104  Utilities->SaveFileString(SessionFile, ProgramVersion + ": ***Interface***" + FloatToStr(TrainController->ExcessLCDownMins));
16105 // added ExcessLC... at v2.2.0 as omitted earlier
16106  SaveInterface(0, SessionFile);
16107  // save track elements
16108  Utilities->SaveFileString(SessionFile, "***Track***");
16109  if(Track->UserGraphicVector.empty())
16110  {
16111  Track->SaveTrack(4, SessionFile, false); // false for no graphics (**Active elements** saved as marker)
16112  }
16113  else
16114  {
16115  Track->SaveTrack(11, SessionFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
16116  }
16117  // save text elements
16118  Utilities->SaveFileString(SessionFile, "***Text***");
16119  TextHandler->SaveText(2, SessionFile);
16120  // save PrefDir elements
16121  Utilities->SaveFileString(SessionFile, "***PrefDirs***");
16122  EveryPrefDir->SavePrefDirVector(2, SessionFile);
16123  if(!Track->UserGraphicVector.empty())
16124  {
16125  // save user graphics
16126  Track->SaveUserGraphics(2, SessionFile);
16127  }
16128  // save routes
16129  Utilities->SaveFileString(SessionFile, "***Routes***");
16130  AllRoutes->SaveRoutes(0, SessionFile);
16131  // save LockedRoutes
16132  Utilities->SaveFileString(SessionFile, "***Locked routes***");
16133  TrainController->SaveSessionLockedRoutes(0, SessionFile);
16134  // save ContinuationAutoSigEntries
16135  Utilities->SaveFileString(SessionFile, "***ContinuationAutoSigEntries***");
16137  // save BarriersDownVector
16138  Utilities->SaveFileString(SessionFile, "***BarriersDownVector***");
16139  Track->SaveSessionBarriersDownVector(0, SessionFile);
16140  // save timetable
16141  Utilities->SaveFileString(SessionFile, "***Timetable***");
16142  if(!(SaveTimetableToSessionFile(0, SessionFile, SessionFileStr)))
16143  {
16144  SessionFile.close();
16145  DeleteFile(SessionFileStr);
16146  Screen->Cursor = TCursor(-2); // Arrow;
16147  TrainController->StopTTClockMessage(3, "Error saving file, unable to save session");
16148  Utilities->CallLogPop(1150);
16149  return;
16150  }
16151  // save TimetableClock
16152  Utilities->SaveFileString(SessionFile, "***TimetableClock***");
16153  Utilities->SaveFileDouble(SessionFile, double(TrainController->TTClockTime));
16154 
16155  // save trains
16156  Utilities->SaveFileString(SessionFile, "***Trains***");
16157  TrainController->SaveSessionTrains(0, SessionFile);
16158  // save performance file
16159  Utilities->SaveFileString(SessionFile, "***Performance file***");
16160  SavePerformanceFile(0, SessionFile);
16161  Utilities->SaveFileString(SessionFile, "***End of performance file***");
16162 // addition at v2.4.0 to save TrainController->AvHoursIntValue + any future additions
16163  Utilities->SaveFileString(SessionFile, "***Additions after v2.3.1***");
16166  Utilities->SaveFileString(SessionFile, "***Failed Trains***");
16167  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
16168  {
16170  {
16173  }
16174  }
16175  Utilities->SaveFileInt(SessionFile, -1); // marker for end of failed trains
16176  Utilities->SaveFileString(SessionFile, "End of file at v2.4.0");
16177 // end of v2.4.0 addition
16178 
16179 // added at v2.7.0
16180  Utilities->SaveFileBool(SessionFile, ConsecSignalsRoute);
16181  Utilities->SaveFileString(SessionFile, "End of file at v2.7.0");
16182 // end of v2.7.0 addition
16183  SessionFile.close();
16184  TrainController->StopTTClockMessage(4, "Session saved: Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " +
16185  RailwayTitle + "; " + TimetableTitle + ".ssn");
16186  LastNonCtrlOrShiftKeyDown = -1; //to restore the ability to reselect Ctrl S after a save (FormKeyUp doesn't work because the Interface form doesn't have focus)
16187  }
16188  else
16189  {
16190  TrainController->StopTTClockMessage(5, "Session file failed to open - reason not known, session unable to be saved.");
16191  }
16193  Screen->Cursor = TCursor(-2); // Arrow
16194  Utilities->CallLogPop(1141);
16195  }
16196  catch(const Exception &e)
16197  {
16198  ErrorLog(40, e.Message);
16199  }
16200 }
16201 
16202 // ---------------------------------------------------------------------------
16203 
16204 void TInterface::LoadSession(int Caller)
16205  // always loads in 'Paused' or 'PreStart' mode
16206 {
16207 // remember to load the timetable clock
16208 // no routes in build
16209 // prob need to set 'OperMode' then 'Paused', ensure have all info needed for these
16210 // set buttons enabled to correspond to flags on reloading. If no PrefDirs then disable all route buttons
16211 // set RlyFile true
16212  try
16213  {
16214  TrainController->LogEvent("LoadSession");
16215  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadSession");
16216  if(!ClearEverything(4))
16217  {
16218  Utilities->CallLogPop(1145);
16219  return;
16220  }
16221  LoadSessionDialog->Filter = "Session file (*.ssn)|*.ssn";
16222  if(LoadSessionDialog->Execute())
16223  {
16224  if(LoadSessionDialog->InitialDir != TPath::GetDirectoryName(LoadSessionDialog->FileName))//new at v2.6.0 to retain a new directory
16225  {
16226  LoadSessionDialog->InitialDir = TPath::GetDirectoryName(LoadSessionDialog->FileName);
16227  }
16228  TrainController->LogEvent("LoadSession " + LoadSessionDialog->FileName);
16229  Screen->Cursor = TCursor(-11); // Hourglass;
16230  if(SessionFileIntegrityCheck(0, AnsiString(LoadSessionDialog->FileName).c_str()))
16231  // if(true)
16232  {
16233  std::ifstream SessionFile(AnsiString(LoadSessionDialog->FileName).c_str());
16234  if(!(SessionFile.fail()))
16235  {
16236  TrainController->AvHoursIntValue = 0; // initial value set at v2.4.0 in case not changed later
16237  TrainController->MTBFHours = 0; // initial value set at v2.4.0 in case not changed later
16238  AnsiString TempString = Utilities->LoadFileString(SessionFile);
16239 // "version + : ***Interface***" + at v2.2.0 ExcessLCDownMins (omitted earlier)
16240 
16241  int LastCharBeforeFloat = TempString.LastDelimiter('*'); // added at v2.2.0
16242  if((LastCharBeforeFloat == 0) || (LastCharBeforeFloat == TempString.Length()))
16243  // can't find it or no value for Excess LCDownMins, either way count as zero
16244  {
16246  }
16247  else
16248  {
16249  AnsiString FloatStr = TempString.SubString(LastCharBeforeFloat + 1, TempString.Length() - LastCharBeforeFloat);
16250  if(!Utilities->CheckStringDouble(FloatStr)) // returns false for empty string or invalid double
16251  {
16253  }
16254  else
16255  {
16256  TrainController->ExcessLCDownMins = FloatStr.ToDouble();
16257  }
16258  } // end of v2.2.0 * v2.4.0 additions
16259 
16260  LoadInterface(0, SessionFile);
16261  int TempDisplayOffsetH = Display->DisplayOffsetH; // stored as they are zeroed when track loaded
16262  int TempDisplayOffsetV = Display->DisplayOffsetV;
16263  int TempDisplayOffsetHHome = Display->DisplayOffsetHHome;
16264  int TempDisplayOffsetVHome = Display->DisplayOffsetVHome;
16265  bool GraphicsFollow = false;
16266  // load track elements
16267  TempString = Utilities->LoadFileString(SessionFile); // ***Track***"
16268  Track->LoadTrack(4, SessionFile, GraphicsFollow);
16269  // load text elements
16270  TempString = Utilities->LoadFileString(SessionFile); // ***Text***"
16271  TextHandler->LoadText(1, SessionFile);
16272  // load PrefDir elements
16273  TempString = Utilities->LoadFileString(SessionFile); // "***PrefDirs***"
16274  EveryPrefDir->LoadPrefDir(1, SessionFile);
16275  if(GraphicsFollow)
16276  {
16277  Track->LoadGraphics(1, SessionFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder);
16278  }
16280  {
16281  SessionFile.close();
16282  Screen->Cursor = TCursor(-2); // Arrow;
16283  ShowMessage("Corruption in preferred direction section of the session file, session can't be loaded");
16284  Utilities->CallLogPop(1438);
16285  return;
16286  }
16287  // load routes
16288  TempString = Utilities->LoadFileString(SessionFile); // "***Routes***"
16289  if(!AllRoutes->LoadRoutes(0, SessionFile))
16290  {
16291  SessionFile.close();
16292  Screen->Cursor = TCursor(-2); // Arrow;
16293  ShowMessage("Corruption in route section of the session file, session can't be loaded");
16294  Utilities->CallLogPop(1439);
16295  return;
16296  }
16297  // load LockedRoutes
16298  TempString = Utilities->LoadFileString(SessionFile); // "***Locked routes***"
16299  TrainController->LoadSessionLockedRoutes(0, SessionFile);
16300  // load ContinuationAutoSigEntries
16301  TempString = Utilities->LoadFileString(SessionFile); // "***ContinuationAutoSigEntries***"
16303  // load BarriersDownVector if present, but ensure backwards compatibility with earlier files
16304  TempString = Utilities->LoadFileString(SessionFile); // "***BarriersDownVector***" or "***Timetable***"
16305  if(TempString == "***BarriersDownVector***")
16306  {
16307  Track->LoadBarriersDownVector(0, SessionFile);
16308  TempString = Utilities->LoadFileString(SessionFile); // "***Timetable***"
16309  }
16310  // load timetable (marker "***Timetable***" already loaded)
16311  if(!(LoadTimetableFromSessionFile(0, SessionFile)))
16312  {
16313  SessionFile.close();
16314  Screen->Cursor = TCursor(-2); // Arrow;
16315  ShowMessage("Unable to load timetable section of the session file, session can't be loaded");
16316  Utilities->CallLogPop(1151);
16317  return;
16318  }
16319  // TimetableTitle should be loaded at this stage - check
16320  if(TimetableTitle == "")
16321  {
16322  SessionFile.close();
16323  Screen->Cursor = TCursor(-2); // Arrow;
16324  throw Exception("TimetableTitle null in LoadSession");
16325  }
16326  // load timetable clock
16327  TempString = Utilities->LoadFileString(SessionFile); // ***TimetableClock***
16328  TrainController->RestartTime = TDateTime(Utilities->LoadFileDouble(SessionFile)); // ClockTime set in RestartSessionOperMode;
16329  // load trains
16330  TempString = Utilities->LoadFileString(SessionFile); // ***Trains***
16331  TrainController->LoadSessionTrains(0, SessionFile);
16332  // load performance file + populate the performance log
16333  TempString = Utilities->LoadFileString(SessionFile); // ***Performance file***
16334  // first reset the performance file name and open it before reloading it
16335  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
16336  // avoid characters in filename:= / \ : * ? " < > |
16337  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " +
16338  TimetableTitle + ".txt";
16339  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
16340  if(Utilities->PerformanceFile.fail())
16341  {
16342  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
16343  " in the folder where the 'Railway.exe' program file resides");
16344  }
16345  // now reload the performance file
16346  LoadPerformanceFile(0, SessionFile);
16347  // addition at v2.4.0
16348  char TempChar;
16349  SessionFile.get(TempChar);
16350  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
16351  {
16352  SessionFile.get(TempChar);
16353  }
16354  if(SessionFile.eof()) // end of file
16355  {
16358  SessionFile.close(); // no TrainController->AvHoursIntValue & no failed trains
16359  //at v2.7.0 if find eof then don't need a value for ConsecSignalsRoute as that loaded same as PreferredRoute in interface
16360  }
16361  else
16362  {
16363  AnsiString DummyStr = Utilities->LoadFileString(SessionFile); // "**Additions after v2.3.1***" discarded (first '*' loaded earlier)
16364  TrainController->AvHoursIntValue = Utilities->LoadFileInt(SessionFile); // TrainController->AvHoursIntValue added at v2.4.0
16365  TrainController->NumFailures = Utilities->LoadFileInt(SessionFile); // number of train failures
16366  TrainController->MTBFHours = TrainController->AvHoursIntValue; // TTClockSpeed set to 1 in RestartSessionMode so no need to include here
16367  // now load any failed trains along with their OriginalPowerAtRail values
16368  DummyStr = Utilities->LoadFileString(SessionFile); // discard "***Failed Trains***"
16369  int ID = Utilities->LoadFileInt(SessionFile); // train ID or -1 for no more failed trains
16370  double PowerDouble;
16371  while(ID != -1)
16372  {
16373  PowerDouble = Utilities->LoadFileDouble(SessionFile); // ok TrainVector loaded at this stage (loaded in LoadSessionTrains)
16376  ID = Utilities->LoadFileInt(SessionFile);
16377  }
16378  //added at v2.7.0 - need value for ConsecSignalsRoute but might have eof here with older sessions so first test for that
16379  DummyStr = Utilities->LoadFileString(SessionFile); // "End of file at v2.4.0" discarded
16380  SessionFile.get(TempChar);
16381  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '0' or '1'
16382  {
16383  SessionFile.get(TempChar);
16384  }
16385  if(!SessionFile.eof()) // not end of file
16386  {
16387  if((TempChar != '0') && (TempChar != '1'))
16388  {
16389  throw Exception("TempChar value = " + AnsiString(TempChar) + ", should be 0 or 1");
16390  }
16391  ConsecSignalsRoute = true;
16392  if(TempChar == '0')
16393  {
16394  ConsecSignalsRoute = false;
16395  }
16396  }
16397  SessionFile.close(); //
16398  }
16399  // deal with other settings
16400  Display->DisplayOffsetH = TempDisplayOffsetH; // reset to saved values
16401  Display->DisplayOffsetV = TempDisplayOffsetV;
16402  Display->DisplayOffsetHHome = TempDisplayOffsetHHome;
16403  Display->DisplayOffsetVHome = TempDisplayOffsetVHome;
16404  // now set attributes to 1 for all LCs with barriers down
16405  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
16406  {
16408  }
16409  Track->ChangingLCVector.clear();
16410  Track->CalcHLocMinEtc(10);
16412  SetLevel1Mode(27);
16413  if(Level2OperMode == PreStart)
16414  // this section added at v1.3.2 as otherwise only in MainScreenMouseDown2, and if load a session without clicking mouse on screen
16415  { // then delay unspecified though seems to be 0
16416  PointsFlashDuration = 0.0;
16419  }
16420  else
16421  {
16425  }
16426  RlyFile = true;
16427  SetCaption(3);
16429  }
16430  }
16431  else
16432  {
16433  ShowMessage("Session file integrity check failed, unable to load session.");
16434  }
16435  Screen->Cursor = TCursor(-2); // Arrow;
16436  }
16437  Utilities->CallLogPop(1146);
16438  }
16439  catch(const Exception &e)
16440  {
16441  if((e.Message.Pos("esource") > 0) || (e.Message.Pos("arameter") > 0)) // 'Resource or Parameter, avoid capitals as may be OS dependent
16442  {
16443  Screen->Cursor = TCursor(-2); // Arrow;
16444  OutputLog1->Caption = "";
16445  OutputLog2->Caption = "";
16446  OutputLog3->Caption = "";
16447  OutputLog4->Caption = "";
16448  OutputLog5->Caption = "";
16449  OutputLog6->Caption = "";
16450  OutputLog7->Caption = "";
16451  OutputLog8->Caption = "";
16452  OutputLog9->Caption = "";
16453  OutputLog10->Caption = "";
16454  UnicodeString MessageStr =
16455  "Insufficient memory available to load the file, and partial load likely to be corrupt. Application will terminate. Try loading the session as the first action after reloading the program.";
16456 // UnicodeString MessageStr = "Last train loaded = " + UnicodeString(TrainController->LastTrainLoaded); //for debugging session train loading for many trains
16457  Application->MessageBox(MessageStr.c_str(), L"Out of memory", MB_OK | MB_ICONERROR);
16458  Application->Terminate();
16459  }
16460  else
16461  {
16462  ErrorLog(41, e.Message);
16463  }
16464  }
16465 }
16466 
16467 // ---------------------------------------------------------------------------
16468 
16469 void TInterface::SaveInterface(int Caller, std::ofstream &SessionFile)
16470 {
16471  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveInterface");
16472  if(Level2OperMode == PreStart)
16473  Utilities->SaveFileString(SessionFile, AnsiString("PreStart"));
16474  else
16475  Utilities->SaveFileString(SessionFile, AnsiString("NotPreStart")); // covers both Paused & Operating
16476  Utilities->SaveFileString(SessionFile, RailwayTitle);
16477  Utilities->SaveFileString(SessionFile, TimetableTitle);
16478  Utilities->SaveFileBool(SessionFile, PreferredRoute);
16479  Utilities->SaveFileBool(SessionFile, PreferredRoute); //changed at v2.7.0, was ConsecSignalsRoute here but if different to PreferredRoute (as can be from v2.7.0) then have
16480  Utilities->SaveFileBool(SessionFile, AutoSigsFlag); //error if try to load with an earlier prog version. ConsecSignalsRoute now moved to end of session file
16481  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetH);
16482  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetV);
16487  Utilities->SaveFileString(SessionFile, OutputLog1->Caption);
16488  Utilities->SaveFileString(SessionFile, OutputLog2->Caption);
16489  Utilities->SaveFileString(SessionFile, OutputLog3->Caption);
16490  Utilities->SaveFileString(SessionFile, OutputLog4->Caption);
16491  Utilities->SaveFileString(SessionFile, OutputLog5->Caption);
16492  Utilities->SaveFileString(SessionFile, OutputLog6->Caption);
16493  Utilities->SaveFileString(SessionFile, OutputLog7->Caption);
16494  Utilities->SaveFileString(SessionFile, OutputLog8->Caption);
16495  Utilities->SaveFileString(SessionFile, OutputLog9->Caption);
16496  Utilities->SaveFileString(SessionFile, OutputLog10->Caption);
16497 
16519  // ExcessLCDownMins saved after ***Interface*** at v2.2.0 (omitted in error earlier)
16520  Utilities->CallLogPop(1211);
16521 }
16522 
16523 // ---------------------------------------------------------------------------
16524 void TInterface::LoadInterface(int Caller, std::ifstream &SessionFile)
16525 {
16526  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadInterface");
16527  AnsiString OpMode = Utilities->LoadFileString(SessionFile);
16528 
16529  if(OpMode == "PreStart")
16531  else
16533  RailwayTitle = Utilities->LoadFileString(SessionFile);
16534  SavedFileName = CurDir + "\\" + RAILWAY_DIR_NAME + "\\" + RailwayTitle + ".rly";
16535 
16536  TimetableTitle = Utilities->LoadFileString(SessionFile);
16537  PreferredRoute = Utilities->LoadFileBool(SessionFile);
16538  ConsecSignalsRoute = Utilities->LoadFileBool(SessionFile);
16539  AutoSigsFlag = Utilities->LoadFileBool(SessionFile);
16540  Display->DisplayOffsetH = Utilities->LoadFileInt(SessionFile);
16541  Display->DisplayOffsetV = Utilities->LoadFileInt(SessionFile);
16546  OutputLog1->Caption = Utilities->LoadFileString(SessionFile);
16547  OutputLog2->Caption = Utilities->LoadFileString(SessionFile);
16548  OutputLog3->Caption = Utilities->LoadFileString(SessionFile);
16549  OutputLog4->Caption = Utilities->LoadFileString(SessionFile);
16550  OutputLog5->Caption = Utilities->LoadFileString(SessionFile);
16551  OutputLog6->Caption = Utilities->LoadFileString(SessionFile);
16552  OutputLog7->Caption = Utilities->LoadFileString(SessionFile);
16553  OutputLog8->Caption = Utilities->LoadFileString(SessionFile);
16554  OutputLog9->Caption = Utilities->LoadFileString(SessionFile);
16555  OutputLog10->Caption = Utilities->LoadFileString(SessionFile);
16556 
16564  TrainController->LateDeps = Utilities->LoadFileInt(SessionFile);
16578  Utilities->CallLogPop(1212);
16579 }
16580 
16581 // ---------------------------------------------------------------------------
16582 
16583 bool TInterface::CheckInterface(int Caller, std::ifstream &SessionFile)
16584 {
16585  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckInterface");
16586 
16587  AnsiString OpMode = "";
16588 
16589  if(!Utilities->CheckAndReadFileString(SessionFile, OpMode))
16590  {
16591  Utilities->CallLogPop(1767);
16592  return false;
16593  }
16594  else if((OpMode != "PreStart") && (OpMode != "NotPreStart"))
16595  {
16596  Utilities->CallLogPop(1768);
16597  return false;
16598  }
16599  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // RailwayTitle
16600  {
16601  Utilities->CallLogPop(1213);
16602  return false;
16603  }
16604  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // TimetableTitle
16605  {
16606  Utilities->CallLogPop(1214);
16607  return false;
16608  }
16609  if(!Utilities->CheckFileBool(SessionFile))
16610  {
16611  Utilities->CallLogPop(1216);
16612  return false;
16613  }
16614  if(!Utilities->CheckFileBool(SessionFile))
16615  {
16616  Utilities->CallLogPop(1217);
16617  return false;
16618  }
16619  if(!Utilities->CheckFileBool(SessionFile))
16620  {
16621  Utilities->CallLogPop(1218);
16622  return false;
16623  }
16624  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16625  {
16626  Utilities->CallLogPop(1409);
16627  return false;
16628  }
16629  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16630  {
16631  Utilities->CallLogPop(1486);
16632  return false;
16633  }
16634  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16635  {
16636  Utilities->CallLogPop(1487);
16637  return false;
16638  }
16639  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16640  {
16641  Utilities->CallLogPop(1488);
16642  return false;
16643  }
16644  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16645  {
16646  Utilities->CallLogPop(1489);
16647  return false;
16648  }
16649  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16650  {
16651  Utilities->CallLogPop(1528);
16652  return false;
16653  }
16654  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16655  {
16656  Utilities->CallLogPop(1725);
16657  return false;
16658  }
16659  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16660  {
16661  Utilities->CallLogPop(1726);
16662  return false;
16663  }
16664  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16665  {
16666  Utilities->CallLogPop(1727);
16667  return false;
16668  }
16669  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16670  {
16671  Utilities->CallLogPop(1728);
16672  return false;
16673  }
16674  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16675  {
16676  Utilities->CallLogPop(1730);
16677  return false;
16678  }
16679  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16680  {
16681  Utilities->CallLogPop(1731);
16682  return false;
16683  }
16684  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16685  {
16686  Utilities->CallLogPop(1732);
16687  return false;
16688  }
16689  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16690  {
16691  Utilities->CallLogPop(1733);
16692  return false;
16693  }
16694  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16695  {
16696  Utilities->CallLogPop(1734);
16697  return false;
16698  }
16699  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16700  {
16701  Utilities->CallLogPop(1789);
16702  return false;
16703  }
16704 
16705  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16706  {
16707  Utilities->CallLogPop(1737);
16708  return false;
16709  }
16710  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16711  {
16712  Utilities->CallLogPop(1738);
16713  return false;
16714  }
16715  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16716  {
16717  Utilities->CallLogPop(1739);
16718  return false;
16719  }
16720  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16721  {
16722  Utilities->CallLogPop(1740);
16723  return false;
16724  }
16725  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16726  {
16727  Utilities->CallLogPop(1741);
16728  return false;
16729  }
16730  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16731  {
16732  Utilities->CallLogPop(1742);
16733  return false;
16734  }
16735  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16736  {
16737  Utilities->CallLogPop(1743);
16738  return false;
16739  }
16740  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16741  {
16742  Utilities->CallLogPop(1744);
16743  return false;
16744  }
16745  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16746  {
16747  Utilities->CallLogPop(1745);
16748  return false;
16749  }
16750  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16751  {
16752  Utilities->CallLogPop(1746);
16753  return false;
16754  }
16755  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16756  {
16757  Utilities->CallLogPop(1747);
16758  return false;
16759  }
16760  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16761  {
16762  Utilities->CallLogPop(1748);
16763  return false;
16764  }
16765  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16766  {
16767  Utilities->CallLogPop(1749);
16768  return false;
16769  }
16770  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16771  {
16772  Utilities->CallLogPop(1750);
16773  return false;
16774  }
16775  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16776  {
16777  Utilities->CallLogPop(1751);
16778  return false;
16779  }
16780  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16781  {
16782  Utilities->CallLogPop(1752);
16783  return false;
16784  }
16785 
16786  if(!Utilities->CheckFileDouble(SessionFile))
16787  {
16788  Utilities->CallLogPop(1753);
16789  return false;
16790  }
16791  if(!Utilities->CheckFileDouble(SessionFile))
16792  {
16793  Utilities->CallLogPop(1754);
16794  return false;
16795  }
16796  if(!Utilities->CheckFileDouble(SessionFile))
16797  {
16798  Utilities->CallLogPop(1755);
16799  return false;
16800  }
16801  if(!Utilities->CheckFileDouble(SessionFile))
16802  {
16803  Utilities->CallLogPop(1756);
16804  return false;
16805  }
16806  if(!Utilities->CheckFileDouble(SessionFile))
16807  {
16808  Utilities->CallLogPop(1757);
16809  return false;
16810  }
16811  Utilities->CallLogPop(1219);
16812  return true;
16813 }
16814 
16815 // ---------------------------------------------------------------------------
16816 
16817 bool TInterface::SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
16818 {
16819  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToSessionFile," + SessionFileStr);
16820  if(!FileExists(TempTTFileName))
16821  {
16822  Utilities->CallLogPop(1862);
16823  return false;
16824  }
16825 
16826  SessionFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
16827  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
16828 
16829  int Handle = FileOpen(TempTTFileName, fmOpenRead);
16830  int Count = 0;
16831 
16832  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
16833  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
16834  // then, but nevertheless have 10 retries before giving message to be on safe side
16835  {
16836  Handle = FileOpen(TempTTFileName, fmOpenRead);
16837  Count++;
16838  Delay(1, 50); // 50mSec delay between tries
16839  if(Count > 10)
16840  {
16841  ShowMessage("Failed to open temporary timetable file. Unable to save the session");
16842  Utilities->CallLogPop(1221);
16843  return false;
16844  }
16845  }
16846 
16847  char *Buffer = new char[10000];
16848  int BytesRead;
16849 
16850  while(true)
16851  {
16852  BytesRead = FileRead(Handle, Buffer, 10000);
16853  SessionFile.write(Buffer, BytesRead);
16854  if(BytesRead < 10000)
16855  break;
16856  }
16857  delete Buffer;
16858  FileClose(Handle);
16859 
16860  SessionFile.close(); // close & re-open in append & text out mode as before so can write text
16861  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
16862 
16863  Utilities->SaveFileString(SessionFile, "***End***"); // marker for end of timetable
16864 // now need to save the TrainOperatingData so can be loaded back into the timetable as is
16865  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.size());
16866  for(unsigned int x = 0; x < TrainController->TrainDataVector.size(); x++)
16867  {
16868  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size());
16869  for(unsigned int y = 0; y < TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size(); y++)
16870  {
16871  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID);
16872  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported));
16873  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry));
16874  }
16875  }
16876  Utilities->CallLogPop(1220);
16877  return true;
16878 }
16879 
16880 // ---------------------------------------------------------------------------
16881 
16882 bool TInterface::SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
16883 {
16884  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToErrorFile," + ErrorFileStr + "," + TimetableFileName);
16885  if(!FileExists(TimetableFileName))
16886  {
16887  Utilities->CallLogPop(1863);
16888  return false;
16889  }
16890 
16891  ErrorFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
16892  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
16893 
16894  int Handle = FileOpen(TimetableFileName, fmOpenRead);
16895  int Count = 0;
16896 
16897  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
16898  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
16899  // then, but nevertheless have 10 retries before giving message to be on safe side
16900  {
16901  Handle = FileOpen(TimetableFileName, fmOpenRead);
16902  Count++;
16903  Delay(5, 50); // 50mSec delay between tries
16904  if(Count > 10)
16905  {
16906  Utilities->CallLogPop(1835);
16907  return false;
16908  }
16909  }
16910 
16911  char *Buffer = new char[10000];
16912  int BytesRead;
16913 
16914  while(true)
16915  {
16916  BytesRead = FileRead(Handle, Buffer, 10000);
16917  ErrorFile.write(Buffer, BytesRead);
16918  if(BytesRead < 10000)
16919  break;
16920  }
16921  delete Buffer;
16922  FileClose(Handle);
16923 
16924  ErrorFile.close(); // close & re-open in append & text out mode as before so can write text
16925  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
16926 
16927  Utilities->SaveFileString(ErrorFile, "***End of timetable***"); // marker for end of timetable
16928  Utilities->CallLogPop(1836);
16929  return true;
16930 }
16931 
16932 // ---------------------------------------------------------------------------
16933 
16934 bool TInterface::LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
16935  // the .ttb section is delimited by "***End***"
16936  // create the temporary timetable file in the working folder exactly like the original
16937 {
16938  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTimetableFromSessionFile");
16939  // reset all message flags, stops them being given twice (shouldn't be needed here but add for safety) //new at v2.4.0
16940  TrainController->SSHigh = false;
16941  TrainController->MRSHigh = false;
16942  TrainController->MRSLow = false;
16943  TrainController->MassHigh = false;
16944  TrainController->BFHigh = false;
16945  TrainController->BFLow = false;
16946  TrainController->PwrHigh = false;
16947  TrainController->SigSHigh = false;
16948  TrainController->SigSLow = false;
16949  if((TempTTFileName != "") && FileExists(TempTTFileName))
16950  {
16951  DeleteFile(TempTTFileName);
16952  }
16953  int TempTTFileNumber = 0;
16954 
16955  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
16956  {
16957  TempTTFileNumber++;
16958  }
16959  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
16960 
16961  std::ofstream TTBFile(TempTTFileName.c_str()); // use text mode as SessionFile is in text mode, so CRLFs read as LFs, and LFs write as CRLFs.
16962  int Count;
16963  char Zero = '\0';
16964 
16965  if(!TTBFile.fail())
16966  {
16967  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
16968  char TempChar = (char)(SessionFile.peek()); // have a look at the next character, if it's '\n'
16969  if(TempChar == '\n')
16970  SessionFile.get(TempChar); // then get rid of it, else leave it in as part of the first line
16971  if(!SessionFile.getline(Buffer, 10000, '\0'))
16972  {
16973  TTBFile.close();
16974  DeleteFile(TempTTFileName);
16975  delete Buffer;
16976  Utilities->CallLogPop(1222);
16977  return false;
16978  }
16979  Count = 0;
16980  for(int x = 0; x < 10000; x++)
16981  {
16982  if(Buffer[x] != '\0')
16983  Count++;
16984  else
16985  break;
16986  }
16987  while(AnsiString(Buffer) != "***End***")
16988  {
16989  TTBFile.write(Buffer, Count);
16990  TTBFile.write(&Zero, 1);
16991 // TTBFile.write(&NewLine, 1);
16992  if(!SessionFile.getline(Buffer, 10000, '\0'))
16993  {
16994  TTBFile.close();
16995  DeleteFile(TempTTFileName);
16996  delete Buffer;
16997  Utilities->CallLogPop(1223);
16998  return false;
16999  }
17000  Count = 0;
17001  for(int x = 0; x < 10000; x++)
17002  {
17003  if(Buffer[x] != '\0')
17004  Count++;
17005  else
17006  break;
17007  }
17008  }
17009  TTBFile.close();
17010  delete Buffer;
17011 // SaveTempTimetableFile(1, TTBFileName); no need, already has required name
17012 // now create the internal timetable from the .tmp file
17013  bool GiveMessagesFalse = false;
17014  bool CheckLocationsExistInRailwayTrue = true;
17015  if(TrainController->TimetableIntegrityCheck(1, TempTTFileName.c_str(), GiveMessagesFalse, CheckLocationsExistInRailwayTrue))
17016  {
17017  std::ifstream TTBLFile(TempTTFileName.c_str(), std::ios_base::binary);
17018  if(TTBLFile.is_open())
17019  {
17020  bool SessionFileTrue = true;
17021  if(!(BuildTrainDataVectorForLoadFile(1, TTBLFile, GiveMessagesFalse, CheckLocationsExistInRailwayTrue, SessionFileTrue)))
17022  {
17023  TTBLFile.close();
17024  DeleteFile(TempTTFileName);
17025  Utilities->CallLogPop(1224);
17026  return false;
17027  }
17028  }
17029  else
17030  {
17031  DeleteFile(TempTTFileName);
17032  Utilities->CallLogPop(1225);
17033  return false;
17034  }
17035  } // if(FileIntegrityCheck(TTBFileName.c_str()))
17036  else
17037  {
17038  DeleteFile(TempTTFileName);
17039  Utilities->CallLogPop(1226);
17040  return false;
17041  }
17042 // DeleteFile(TempTTFileName); no, need to save it for later session saves
17043 
17044  // now need to load the TrainOperatingData so can be loaded back into the timetable
17045  int NumberOfTrainEntries = Utilities->LoadFileInt(SessionFile);
17046  if(NumberOfTrainEntries != (int)(TrainController->TrainDataVector.size()))
17047  {
17048  Utilities->CallLogPop(1811);
17049  return false;
17050  }
17051  for(int x = 0; x < NumberOfTrainEntries; x++)
17052  {
17053  int NumberOfTrains = Utilities->LoadFileInt(SessionFile);
17054  if(NumberOfTrains != (int)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size()))
17055  {
17056  Utilities->CallLogPop(1812);
17057  return false;
17058  }
17059  for(int y = 0; y < NumberOfTrains; y++)
17060  {
17061  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID = Utilities->LoadFileInt(SessionFile);
17062  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported = (TActionEventType)(Utilities->LoadFileInt(SessionFile));
17063  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry = (TRunningEntry)(Utilities->LoadFileInt(SessionFile));
17064  }
17065  }
17066  Utilities->CallLogPop(1227);
17067  return true;
17068  }
17069  else
17070  {
17071  Utilities->CallLogPop(1228);
17072  return false;
17073  }
17074 }
17075 
17076 // ---------------------------------------------------------------------------
17077 
17078 bool TInterface::CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
17079  // the .ttb section is delimited by '\0' followed by "***End***" & has been saved in binary mode, i.e. no '\0'
17080  // string delimiters between entries, this check function just checks the (non-zero terminated) string entries in the file without
17081  // trying to build a timetable - that's done during load
17082 {
17083  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTimetableFromSessionFile");
17084  AnsiString OutString;
17085 
17086  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
17087  {
17088  Utilities->CallLogPop(1229);
17089  return false;
17090  }
17091  while(OutString != "***End***")
17092  {
17093  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
17094  {
17095  Utilities->CallLogPop(1230);
17096  return false;
17097  }
17098  }
17099 // now need to check the TrainOperatingData, which was saved in text mode
17100  if(SessionFile.fail())
17101  {
17102  Utilities->CallLogPop(1231);
17103  return false;
17104  }
17105  int NumberOfTrainEntries;
17106 
17107  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrainEntries))
17108  {
17109  Utilities->CallLogPop(1232);
17110  return false;
17111  }
17112  for(int x = 0; x < NumberOfTrainEntries; x++)
17113  {
17114  int NumberOfTrains;
17115  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrains))
17116  {
17117  Utilities->CallLogPop(1233);
17118  return false;
17119  }
17120  for(int y = 0; y < NumberOfTrains; y++)
17121  {
17122  if(!Utilities->CheckFileInt(SessionFile, -1, 1000000)) // TrainID
17123  {
17124  Utilities->CallLogPop(1234);
17125  return false;
17126  }
17127  if(!Utilities->CheckFileInt(SessionFile, 0, 30)) // EventReported
17128  {
17129  Utilities->CallLogPop(1235);
17130  return false;
17131  }
17132  if(!Utilities->CheckFileInt(SessionFile, 0, 2)) // RunningEntry
17133  {
17134  Utilities->CallLogPop(1236);
17135  return false;
17136  }
17137  }
17138  }
17139  Utilities->CallLogPop(1237);
17140  return true;
17141 }
17142 
17143 // ---------------------------------------------------------------------------
17144 
17145 bool TInterface::BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
17146 {
17147  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForLoadFile," + AnsiString((short)GiveMessages));
17148  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
17149  bool EndOfFile = false;
17150  int Count = 0;
17151  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
17152 
17153  while(!EndOfFile)
17154  {
17155  TTBLFile.getline(TrainTimetableString, 10000, '\0');
17156  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
17157  { // may still have eof even if read a line (no CRLF at end), and
17158  // if so need to process it
17159  EndOfFile = true;
17160  break;
17161  }
17162  AnsiString OneLine(TrainTimetableString);
17163  bool FinalCallTrue = true;
17164  while((Count == 0) && !TrainController->ProcessOneTimetableLine(3, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
17165  CheckLocationsExistInRailway)) // get rid of lines before the start time
17166  {
17167  TTBLFile.getline(TrainTimetableString, 10000, '\0');
17168  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
17169  {
17170  TTBLFile.close();
17171  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
17172  }
17173  OneLine = AnsiString(TrainTimetableString);
17174  }
17175  // here when have accepted the start time
17176  if(Count == 0)
17177  {
17178  Count++; // increment past the start time
17179  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
17180  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
17181  {
17182  EndOfFile = true;
17183  OneLine = "";
17184  }
17185  else
17186  OneLine = AnsiString(TrainTimetableString);
17187  }
17188  if(!TrainController->ProcessOneTimetableLine(4, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
17189  {
17190  TTBLFile.close();
17191  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
17192  }
17193  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
17194  {
17195  TTBLFile.close();
17196  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
17197  }
17198  Count++;
17199  }
17200  TTBLFile.close();
17201  delete TrainTimetableString;
17202 // here when first pass actions completed successfully
17203  if(!TrainController->SecondPassActions(0, GiveMessages)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
17204  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
17205  // messages given in function if errors & vector cleared
17206  {
17207  if(GiveMessages)
17208  ShowMessage("Timetable secondary integrity check failed - unable to load");
17209  Utilities->CallLogPop(1238);
17210  return false;
17211  }
17212  else
17213  {
17214 // TimetableLoaded = true;
17215  if(!SessionFile) // new timetable being loaded so need new TimetableTitle, if SessionFile true then already have it from LoadInterface
17216  {
17217  for(int x = TimetableDialog->FileName.Length(); x > 0; x--)
17218  {
17219  if(TimetableDialog->FileName[x] == '\\')
17220  {
17221  TimetableTitle = TimetableDialog->FileName.SubString(x + 1, TimetableDialog->FileName.Length() - x - 4);
17222  SetCaption(4);
17223  break;
17224  }
17225  }
17226  }
17227 // if(GiveMessages) //only set BaseMode if have manually loaded a timetable changed for the below in v2.4.0
17228  if(!SessionFile) // only set BaseMode if have manually loaded a timetable, i.e SessionFile is false
17229  {
17230  Level1Mode = BaseMode;
17231  SetLevel1Mode(28);
17232  }
17233  }
17234  Utilities->CallLogPop(1239);
17235  return true;
17236 }
17237 
17238 // ---------------------------------------------------------------------------
17239 
17240 bool TInterface::BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
17241 {
17242  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForValidateFile," + AnsiString((short)GiveMessages));
17243  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
17244  bool EndOfFile = false;
17245  int Count = 0;
17246  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
17247 
17248  while(!EndOfFile)
17249  {
17250  TTBLFile.getline(TrainTimetableString, 10000, '\0');
17251  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
17252  { // may still have eof even if read a line (no CRLF at end), and
17253  // if so need to process it
17254  EndOfFile = true;
17255  break;
17256  }
17257  AnsiString OneLine(TrainTimetableString);
17258  bool FinalCallTrue = true;
17259  while((Count == 0) && !TrainController->ProcessOneTimetableLine(0, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
17260  CheckLocationsExistInRailway)) // get rid of lines before the start time
17261  {
17262  TTBLFile.getline(TrainTimetableString, 10000, '\0');
17263  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
17264  {
17265  TTBLFile.close();
17266  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
17267  }
17268  OneLine = AnsiString(TrainTimetableString);
17269  }
17270  // here when have accepted the start time
17271  if(Count == 0)
17272  {
17273  Count++; // increment past the start time
17274  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
17275  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
17276  {
17277  EndOfFile = true;
17278  OneLine = "";
17279  }
17280  else
17281  OneLine = AnsiString(TrainTimetableString);
17282  }
17283  if(!TrainController->ProcessOneTimetableLine(1, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
17284  {
17285  TTBLFile.close();
17286  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
17287  }
17288  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
17289  {
17290  TTBLFile.close();
17291  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
17292  }
17293  Count++;
17294  }
17295  TTBLFile.close();
17296  delete TrainTimetableString;
17297 // here when first pass actions completed successfully
17298  if(!TrainController->SecondPassActions(1, GiveMessages)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
17299  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
17300  // messages given in function if errors & vector cleared
17301  {
17302 // if(GiveMessages) ShowMessage("Timetable secondary integrity check failed");
17303 // above dropped in v2.4.0 as all called functions give own messages
17304  Utilities->CallLogPop(1665);
17305  return false;
17306  }
17307  Utilities->CallLogPop(1666);
17308  return true;
17309 }
17310 
17311 // ---------------------------------------------------------------------------
17312 
17313 bool TInterface::SessionFileIntegrityCheck(int Caller, AnsiString FileName)
17314 /* Here need to check as far as timetable, then go back and load the track, because the timetable compilation check
17315  relies on the track vector and map being in place. Won't affect the later load because the vector and map are cleared
17316  before loading.
17317 
17318  Although this appears cumbersome, I initially used tellg() & seekg() to reposition the file pointer without having to do
17319  all this backtracking. However after many problems I eventually found that tellg() sometimes returns false values,
17320  which cause problems when reloaded using seekg(). This must be a compiler problem, though I could find no mention of it
17321  in the CBuilder4 issues list or on the web. The full write-up is at the end of this unit.
17322 
17323  Also, with hindsight, I wish I had just saved and reloaded the timetable vectors rather than the text of the timetable. That
17324  would probably have been easier. To change it now though would cause compatibility problems with sessions created by earlier versions.
17325 */
17326 {
17327  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SessionFileIntegrityCheck," + FileName);
17328  std::ifstream InFile(FileName.c_str());
17329 // first pass as far as timetable
17330  int NumberOfActiveElements;
17331  bool GraphicsFollow = false;
17332 
17333  if(InFile.is_open())
17334  {
17336  // expected to be "***Interface***" for original version or "Version + : ***Interface***" for later releases + ExcessLCDownMins added as float after v2.2.0
17337  {
17338  InFile.close();
17339  Utilities->CallLogPop(1240);
17340  return false;
17341  }
17342  if(!CheckInterface(0, InFile))
17343  {
17344  InFile.close();
17345  Utilities->CallLogPop(1241);
17346  return false;
17347  }
17348  // check track elements
17349  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
17350  {
17351  InFile.close();
17352  Utilities->CallLogPop(1242);
17353  return false;
17354  }
17355  if(!Track->CheckTrackElementsInFile(2, NumberOfActiveElements, GraphicsFollow, InFile))
17356  {
17357  InFile.close();
17358  Utilities->CallLogPop(1243);
17359  return false;
17360  }
17361  if(InFile.fail())
17362  {
17363  InFile.close();
17364  Utilities->CallLogPop(1244);
17365  return false;
17366  }
17367  // check text elements
17368  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
17369  {
17370  InFile.close();
17371  Utilities->CallLogPop(1245);
17372  return false;
17373  }
17374  if(!TextHandler->CheckTextElementsInFile(1, InFile))
17375  {
17376  InFile.close();
17377  Utilities->CallLogPop(1246);
17378  return false;
17379  }
17380  if(InFile.fail())
17381  {
17382  InFile.close();
17383  Utilities->CallLogPop(1247);
17384  return false;
17385  }
17386  // check PrefDir elements
17387  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
17388  {
17389  InFile.close();
17390  Utilities->CallLogPop(1248);
17391  return false;
17392  }
17393  if(!EveryPrefDir->CheckOnePrefDir(1, NumberOfActiveElements, InFile))
17394  {
17395  InFile.close();
17396  Utilities->CallLogPop(1249);
17397  return false;
17398  }
17399  if(InFile.fail())
17400  {
17401  InFile.close();
17402  Utilities->CallLogPop(1250);
17403  return false;
17404  }
17405  // check graphics
17406  if(GraphicsFollow)
17407  {
17408  if(!Track->CheckUserGraphics(1, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
17409  {
17410  InFile.close();
17411  Utilities->CallLogPop(2187);
17412  return false;
17413  }
17414  if(InFile.fail())
17415  {
17416  InFile.close();
17417  Utilities->CallLogPop(2188);
17418  return false;
17419  }
17420  }
17421  // check routes
17422  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
17423  {
17424  InFile.close();
17425  Utilities->CallLogPop(1251);
17426  return false;
17427  }
17428  if(!AllRoutes->CheckRoutes(0, NumberOfActiveElements, InFile))
17429  {
17430  InFile.close();
17431  Utilities->CallLogPop(1252);
17432  return false;
17433  }
17434  if(InFile.fail())
17435  {
17436  InFile.close();
17437  Utilities->CallLogPop(1253);
17438  return false;
17439  }
17440  // check LockedRoutes
17441  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
17442  {
17443  InFile.close();
17444  Utilities->CallLogPop(1254);
17445  return false;
17446  }
17447  if(!TrainController->CheckSessionLockedRoutes(0, InFile))
17448  {
17449  InFile.close();
17450  Utilities->CallLogPop(1255);
17451  return false;
17452  }
17453  if(InFile.fail())
17454  {
17455  InFile.close();
17456  Utilities->CallLogPop(1256);
17457  return false;
17458  }
17459  // check ContinuationAutoSigs
17460  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
17461  {
17462  InFile.close();
17463  Utilities->CallLogPop(1257);
17464  return false;
17465  }
17467  {
17468  InFile.close();
17469  Utilities->CallLogPop(1258);
17470  return false;
17471  }
17472  if(InFile.fail())
17473  {
17474  InFile.close();
17475  Utilities->CallLogPop(1259);
17476  return false;
17477  }
17478  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
17479  AnsiString TempString = Utilities->LoadFileString(InFile);
17480  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
17481  {
17482  InFile.close();
17483  Utilities->CallLogPop(1964);
17484  return false;
17485  }
17486  if(TempString == "***BarriersDownVector***")
17487  {
17488  if(!Track->CheckActiveLCVector(0, InFile))
17489  {
17490  InFile.close();
17491  Utilities->CallLogPop(1965);
17492  return false;
17493  }
17494  if(InFile.fail())
17495  {
17496  InFile.close();
17497  Utilities->CallLogPop(1966);
17498  return false;
17499  }
17500  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
17501  {
17502  InFile.close();
17503  Utilities->CallLogPop(1260);
17504  return false;
17505  }
17506  }
17507  // check timetable (marker string already checked immediately above)
17508  if(!CheckTimetableFromSessionFile(0, InFile))
17509  {
17510  InFile.close();
17511  Utilities->CallLogPop(1261);
17512  return false;
17513  }
17514  if(InFile.fail())
17515  {
17516  InFile.close();
17517  Utilities->CallLogPop(1262);
17518  return false;
17519  }
17520  }
17521  else
17522  {
17523  InFile.close();
17524  ShowMessage("Session file failed to open - reason not known, unable to load session.");
17525  Utilities->CallLogPop(1263);
17526  return false;
17527  }
17528 
17529 // now ready for the 2nd pass for timetable loading and checking
17530  InFile.close();
17531  InFile.open(FileName.c_str());
17532  if(InFile.is_open())
17533  {
17535  {
17536  InFile.close();
17537  Utilities->CallLogPop(1264);
17538  return false;
17539  }
17540  if(!CheckInterface(1, InFile))
17541  {
17542  InFile.close();
17543  Utilities->CallLogPop(1265);
17544  return false;
17545  }
17546  // load track elements
17547  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
17548  {
17549  InFile.close();
17550  Utilities->CallLogPop(1266);
17551  return false;
17552  }
17553  bool GraphicsFollow = false;
17554  Track->LoadTrack(2, InFile, GraphicsFollow); // load the track this time
17555  if(InFile.fail())
17556  {
17557  InFile.close();
17558  Utilities->CallLogPop(1267);
17559  return false;
17560  }
17561  // check text elements
17562  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
17563  {
17564  InFile.close();
17565  Utilities->CallLogPop(1268);
17566  return false;
17567  }
17568  if(!TextHandler->CheckTextElementsInFile(2, InFile))
17569  {
17570  InFile.close();
17571  Utilities->CallLogPop(1269);
17572  return false;
17573  }
17574  if(InFile.fail())
17575  {
17576  InFile.close();
17577  Utilities->CallLogPop(1270);
17578  return false;
17579  }
17580  // check PrefDir elements
17581  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
17582  {
17583  InFile.close();
17584  Utilities->CallLogPop(1271);
17585  return false;
17586  }
17587  if(!EveryPrefDir->CheckOnePrefDir(2, NumberOfActiveElements, InFile))
17588  {
17589  InFile.close();
17590  Utilities->CallLogPop(1272);
17591  return false;
17592  }
17593  if(InFile.fail())
17594  {
17595  InFile.close();
17596  Utilities->CallLogPop(1273);
17597  return false;
17598  }
17599  // check graphics
17600  if(GraphicsFollow)
17601  {
17602  if(!Track->CheckUserGraphics(2, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
17603  {
17604  InFile.close();
17605  Utilities->CallLogPop(2189);
17606  return false;
17607  }
17608  if(InFile.fail())
17609  {
17610  InFile.close();
17611  Utilities->CallLogPop(2190);
17612  return false;
17613  }
17614  }
17615  // check routes
17616  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
17617  {
17618  InFile.close();
17619  Utilities->CallLogPop(1274);
17620  return false;
17621  }
17622  if(!AllRoutes->CheckRoutes(1, NumberOfActiveElements, InFile))
17623  {
17624  InFile.close();
17625  Utilities->CallLogPop(1275);
17626  return false;
17627  }
17628  if(InFile.fail())
17629  {
17630  InFile.close();
17631  Utilities->CallLogPop(1276);
17632  return false;
17633  }
17634  // check LockedRoutes
17635  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
17636  {
17637  InFile.close();
17638  Utilities->CallLogPop(1277);
17639  return false;
17640  }
17641  if(!TrainController->CheckSessionLockedRoutes(1, InFile))
17642  {
17643  InFile.close();
17644  Utilities->CallLogPop(1278);
17645  return false;
17646  }
17647  if(InFile.fail())
17648  {
17649  InFile.close();
17650  Utilities->CallLogPop(1279);
17651  return false;
17652  }
17653  // check ContinuationAutoSigs
17654  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
17655  {
17656  InFile.close();
17657  Utilities->CallLogPop(1280);
17658  return false;
17659  }
17661  {
17662  InFile.close();
17663  Utilities->CallLogPop(1281);
17664  return false;
17665  }
17666  if(InFile.fail())
17667  {
17668  InFile.close();
17669  Utilities->CallLogPop(1282);
17670  return false;
17671  }
17672  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
17673  AnsiString TempString = Utilities->LoadFileString(InFile);
17674  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
17675  {
17676  InFile.close();
17677  Utilities->CallLogPop(1967);
17678  return false;
17679  }
17680  if(TempString == "***BarriersDownVector***")
17681  {
17682  if(!Track->CheckActiveLCVector(0, InFile))
17683  {
17684  InFile.close();
17685  Utilities->CallLogPop(1968);
17686  return false;
17687  }
17688  if(InFile.fail())
17689  {
17690  InFile.close();
17691  Utilities->CallLogPop(1969);
17692  return false;
17693  }
17694  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
17695  {
17696  InFile.close();
17697  Utilities->CallLogPop(1283);
17698  return false;
17699  }
17700  }
17701  // check timetable (marker string already checked)
17702  if(!LoadTimetableFromSessionFile(1, InFile))
17703  {
17704  InFile.close();
17705  Utilities->CallLogPop(1284);
17706  return false;
17707  }
17708  if(InFile.fail())
17709  {
17710  InFile.close();
17711  Utilities->CallLogPop(1285);
17712  return false;
17713  }
17714  // check timetable clock
17715  if(!Utilities->CheckAndCompareFileString(InFile, "***TimetableClock***"))
17716  {
17717  InFile.close();
17718  Utilities->CallLogPop(1286);
17719  return false;
17720  }
17721  if(!Utilities->CheckFileDouble(InFile))
17722  {
17723  InFile.close();
17724  Utilities->CallLogPop(1287);
17725  return false;
17726  }
17727  // check trains
17728  if(!Utilities->CheckAndCompareFileString(InFile, "***Trains***"))
17729  {
17730  InFile.close();
17731  Utilities->CallLogPop(1288);
17732  return false;
17733  }
17734  if(!TrainController->CheckSessionTrains(0, InFile))
17735  {
17736  InFile.close();
17737  Utilities->CallLogPop(1289);
17738  return false;
17739  }
17740  if(InFile.fail())
17741  {
17742  InFile.close();
17743  Utilities->CallLogPop(1290);
17744  return false;
17745  }
17746  if(!Utilities->CheckAndCompareFileString(InFile, "***Performance file***"))
17747  {
17748  InFile.close();
17749  Utilities->CallLogPop(1291);
17750  return false;
17751  }
17752  if(!CheckPerformanceFile(0, InFile))
17753  {
17754  InFile.close();
17755  Utilities->CallLogPop(1292);
17756  return false;
17757  }
17758  char TempChar;
17759  InFile.get(TempChar);
17760  while(!InFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
17761  {
17762  InFile.get(TempChar);
17763  }
17764  if(!InFile.eof()) // additional checks needed
17765  {
17766  if(!Utilities->CheckFileString(InFile))
17767  {
17768  InFile.close();
17769  Utilities->CallLogPop(2198);
17770  return false;
17771  }
17772  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // TrainController->AvHoursIntValue
17773  {
17774  InFile.close();
17775  Utilities->CallLogPop(2199);
17776  return false;
17777  }
17778  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // number of train failures
17779  {
17780  InFile.close();
17781  Utilities->CallLogPop(2200);
17782  return false;
17783  }
17784  // now check any failed trains along with their OriginalPowerAtRail values
17785  Utilities->CheckFileString(InFile); // discard "***Failed Trains***"
17786  int IDVal;
17787  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal)) // train ID or -1 for no more failed trains,
17788  {
17789  InFile.close();
17790  Utilities->CallLogPop(2201);
17791  return false;
17792  }
17793  double PowerDouble;
17794  while(IDVal != -1)
17795  {
17796  Utilities->CheckFileDouble(InFile); // original power
17797  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal))
17798  {
17799  InFile.close();
17800  Utilities->CallLogPop(2202);
17801  return false;
17802  }
17803  }
17804  }
17805  InFile.close();
17806  }
17807  else
17808  {
17809  InFile.close();
17810  Utilities->CallLogPop(1293);
17811  return false;
17812  }
17813  Utilities->CallLogPop(1294);
17814  return true;
17815 }
17816 
17817 // ---------------------------------------------------------------------------
17818 
17819 void TInterface::LoadPerformanceFile(int Caller, std::ifstream &InFile)
17820  // Note that the file integrity has already been checked using CheckPerformanceFile
17821 {
17822  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPerformanceFile");
17823  AnsiString TempString = "", Line1 = "", Line2 = "", Line3 = "", Line4 = "", Line5 = "";
17824  char *Buffer = new char[1000];
17825  char TempChar;
17826 
17827  InFile.get(TempChar); // '\n'
17828  InFile.getline(Buffer, 1000);
17829  TempString = AnsiString(Buffer);
17830  while(TempString != "***End of performance file***")
17831  {
17832  PerformanceLogBox->Lines->Add(TempString);
17833  Utilities->PerformanceFile << TempString.c_str() << '\n';
17834  InFile.getline(Buffer, 1000);
17835  TempString = AnsiString(Buffer);
17836  }
17837  delete Buffer;
17838  Utilities->CallLogPop(1295);
17839 }
17840 
17841 // ---------------------------------------------------------------------------
17842 
17843 bool TInterface::CheckPerformanceFile(int Caller, std::ifstream &InFile)
17844 {
17845  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPerformanceFile");
17846  AnsiString TempString = "";
17847  char TempChar;
17848 
17849  InFile.get(TempChar);
17850  if(TempChar != '\n')
17851  {
17852  Utilities->CallLogPop(1296);
17853  return false;
17854  }
17855  if(!Utilities->CheckAndReadFileString(InFile, TempString))
17856  {
17857  Utilities->CallLogPop(1297);
17858  return false;
17859  }
17860  while(TempString != "***End of performance file***")
17861  {
17862  if(!Utilities->CheckAndReadFileString(InFile, TempString))
17863  {
17864  Utilities->CallLogPop(1298);
17865  return false;
17866  }
17867  }
17868  Utilities->CallLogPop(1299);
17869  return true;
17870 }
17871 
17872 // ---------------------------------------------------------------------------
17873 
17874 void TInterface::SavePerformanceFile(int Caller, std::ofstream &OutFile)
17875 {
17876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePerformanceFile");
17877  AnsiString Text = PerformanceLogBox->Text;
17878 
17879  while(Text != "")
17880  {
17881  AnsiString OneLine = Text.SubString(1, Text.Pos('\x0D'));
17882  while((OneLine.Length() > 0) && OneLine[OneLine.Length()] < ' ')
17883  OneLine.SetLength(OneLine.Length() - 1); // get rid of trailing control characters
17884  Text = Text.SubString(Text.Pos('\x0D'), Text.Length());
17885  while((Text.Length() > 0) && Text[1] < ' ')
17886  Text = Text.SubString(2, (Text.Length() - 1)); // get rid of leading control characters
17887  OutFile << OneLine.c_str() << '\n';
17888  }
17889  Utilities->CallLogPop(1300);
17890 }
17891 
17892 // ---------------------------------------------------------------------------
17893 
17895 {
17896  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteButtonsInfoCaptionAndRouteNotStarted");
17897  if(EveryPrefDir->PrefDirSize() > 0)
17898  {
17899  if(AutoSigsFlag)
17900  {
17901  AutoSigsButton->Enabled = false;
17902  SigPrefConsecButton->Enabled = true;
17903  SigPrefNonConsecButton->Enabled = true;
17904  UnrestrictedButton->Enabled = true;
17905  InfoPanel->Visible = true;
17906  if(Level2OperMode == PreStart)
17907  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
17908  else
17909  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
17910  InfoCaptionStore = InfoPanel->Caption;
17911  }
17912  else if(PreferredRoute & ConsecSignalsRoute) //added at v2.7.0, was just ConsecSignalsRoute
17913  {
17914  AutoSigsButton->Enabled = true;
17915  SigPrefConsecButton->Enabled = false;
17916  SigPrefNonConsecButton->Enabled = true;
17917  UnrestrictedButton->Enabled = true;
17918  InfoPanel->Visible = true;
17919  if(Level2OperMode == PreStart)
17920  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
17921  else
17922  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
17923  InfoCaptionStore = InfoPanel->Caption;
17924  }
17925  else if(PreferredRoute & !ConsecSignalsRoute) //added at v2.7.0
17926  {
17927  AutoSigsButton->Enabled = true;
17928  SigPrefConsecButton->Enabled = true;
17929  SigPrefNonConsecButton->Enabled = false;
17930  UnrestrictedButton->Enabled = true;
17931  InfoPanel->Visible = true;
17932  if(Level2OperMode == PreStart)
17933  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
17934  else
17935  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
17936  InfoCaptionStore = InfoPanel->Caption;
17937  }
17938  else
17939  {
17940  AutoSigsButton->Enabled = true;
17941  SigPrefConsecButton->Enabled = true;
17942  SigPrefNonConsecButton->Enabled = true;
17943  UnrestrictedButton->Enabled = false;
17944  InfoPanel->Visible = true;
17945  if(Level2OperMode == PreStart)
17946  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17947  else
17948  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17949  InfoCaptionStore = InfoPanel->Caption;
17950  }
17951  }
17952  else
17953  {
17954  AutoSigsButton->Enabled = false;
17955  SigPrefConsecButton->Enabled = false;
17956  SigPrefNonConsecButton->Enabled = false;
17957  UnrestrictedButton->Enabled = false;
17958  InfoPanel->Visible = true;
17959  if(Level2OperMode == PreStart)
17960  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17961  else
17962  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17963  InfoCaptionStore = InfoPanel->Caption;
17964  }
17966  {
17967  RouteCancelButton->Enabled = true;
17968  }
17969  else
17970  {
17971  RouteCancelButton->Enabled = false;
17972  }
17974  AutoRouteStartMarker->PlotOriginal(37, Display); // so start marker will replot if had selected start before pause & zoom
17977  Utilities->CallLogPop(1301);
17978 }
17979 
17980 // ---------------------------------------------------------------------------
17981 
17983 {
17984  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetPausedOrZoomedInfoCaption");
17985  if(Display->ZoomOutFlag)
17986  {
17987  InfoPanel->Visible = true;
17988  InfoPanel->Caption = "Left click screen to zoom in at that position";
17989  }
17990  else if(Level2OperMode == Paused)
17991  {
17992  InfoPanel->Visible = true;
17993  InfoPanel->Caption = "PAUSED: Railway state changes disabled";
17994  }
17995 // otherwise do nothing
17996  Utilities->CallLogPop(1302);
17997 }
17998 
17999 // ---------------------------------------------------------------------------
18000 
18002 {
18003  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisableRouteButtons");
18004  RouteCancelButton->Enabled = false;
18005  AutoSigsButton->Enabled = false;
18006  SigPrefConsecButton->Enabled = false;
18007  SigPrefNonConsecButton->Enabled = false;
18008  UnrestrictedButton->Enabled = false;
18009  Utilities->CallLogPop(1303);
18010 }
18011 
18012 // ---------------------------------------------------------------------------
18013 
18015  // no need for call logging as already failed
18016 {
18017 /*
18018  In order to reload as a session file:
18019 
18020  NB: Don't change it to a .txt file, as the '\0' characters [shown as a small square in wordpad] will be changed to spaces if it is subsequently saved
18021  strip out:-
18022 
18023  [since adding user graphics after prefdirs need to take this into account]
18024 
18025  up to but excluding ***Interface***
18026  from & including ***ConstructPrefDir PrefDirVector***
18027  to but excluding ***PrefDirs***
18028  if there is a single line ***UserGraphics*** delete it (won't be present if no graphics)
18029  from & including ***ConstructRoute PrefDirVector***
18030  to but excluding ***Routes***
18031  from & including ***ChangingLCVector*** to but excluding ***Timetable*** [if have ***No timetable loaded*** then can't use as a session file]
18032  from & including ***No editing timetable*** or ***Editing timetable - [title]***
18033  to but excluding ***TimetableClock***
18034  and save as a .ssn file.
18035 
18036  In order to load as a railway file:
18037 
18038  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
18039 
18040  note or copy the version information at the top of the file
18041  copy the two numbers on rows 7 & 8 below ***Interface*** (i.e ***Interface*** = row 0) on their own lines immediately after the ***Track*** line (these become DisplayOffsetH & V)
18042  strip out up to but excluding ***Track*** - this is needed to keep the \0 entry at end of ***Track*** [shown as a small square in wordpad]
18043  add the version number either before or instead of ***Track***, ensuring that the \0 is retained
18044  the next line after the two insertions should contain the number of active elements.
18045  strip out ***Text*** including the \0
18046  strip out from & including ***ConstructPrefDir PrefDirVector*** to & including ***PrefDirs*** (and the \0's)
18047  strip out ***UserGraphics*** including the \0
18048  strip out from & including ***ConstructRoute PrefDirVector*** to the end of the file
18049  rename as .dev or .rly file
18050 
18051  BUT - note that signals (and points, though they won't show) will be set as they were left. To reset to red, load a suitable timetable & select
18052  'Operate' then 'Exit operation'.
18053 */
18054 
18055 /*
18056  In order to extract a timetable:
18057 
18058  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
18059 
18060  set wordwrap to window on
18061  strip out all to and including ***Timetable*** or ***Editing timetable.... depending which is to be saved
18062  ensure any text before start time ends with /0, otherwise don't need the \0
18063  strip out all after the final /0 immediately before ***End*** or ***End of timetable***, but ensure leave the final /0
18064  save as a .ttb file
18065 */
18066 
18067  Screen->Cursor = TCursor(-11); // Hourglass;
18068  AnsiString ErrorFileStr = CurDir + "\\errorlog.err";
18069  std::ofstream ErrorFile(ErrorFileStr.c_str());
18070 
18071  if(!(ErrorFile.fail()))
18072  {
18073 // save mouse position relative to mainscreen
18074  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
18075  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
18076  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
18077  Utilities->SaveFileString(ErrorFile, MouseStr);
18078  Utilities->SaveFileInt(ErrorFile, MissedTicks);
18079  Utilities->SaveFileInt(ErrorFile, TotalTicks);
18080 
18081 // save call stack
18082  Utilities->SaveFileString(ErrorFile, "***Call stack***");
18083  for(unsigned int x = 0; x < Utilities->CallLog.size(); x++)
18084  {
18085  AnsiString Item = Utilities->CallLog.at(x);
18086  ErrorFile << Item.c_str() << '\n';
18087  }
18088 // save event log
18089  Utilities->SaveFileString(ErrorFile, "***Event log***");
18090  for(unsigned int x = 0; x < Utilities->EventLog.size(); x++)
18091  {
18092  AnsiString Item = Utilities->EventLog.at(x);
18093  ErrorFile << Item.c_str() << '\n';
18094  }
18095 // save interface
18096  Utilities->SaveFileString(ErrorFile, "***Interface***");
18097  SaveInterface(1, ErrorFile);
18098 // save track elements
18099  Utilities->SaveFileString(ErrorFile, "***Track***");
18100  if(Track->UserGraphicVector.empty())
18101  {
18102  Track->SaveTrack(2, ErrorFile, false); // false for no graphics (**Active elements** saved as marker)
18103  }
18104  else
18105  {
18106  Track->SaveTrack(12, ErrorFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
18107  }
18108 // save text elements
18109  Utilities->SaveFileString(ErrorFile, "***Text***");
18110  TextHandler->SaveText(3, ErrorFile);
18111 // save ConstructPrefDir PrefDirVector elements
18112  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir PrefDirVector***");
18113  ConstructPrefDir->SavePrefDirVector(7, ErrorFile);
18114 // save ConstructPrefDir SearchVector elements
18115  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir SearchVector***");
18116  ConstructPrefDir->SaveSearchVector(0, ErrorFile);
18117 // save EveryPrefDir elements
18118  Utilities->SaveFileString(ErrorFile, "***PrefDirs***");
18119  EveryPrefDir->SavePrefDirVector(3, ErrorFile);
18120  if(!Track->UserGraphicVector.empty())
18121  {
18122  // save user graphics
18123  Utilities->SaveFileString(ErrorFile, "***UserGraphics***");
18124  Track->SaveUserGraphics(3, ErrorFile);
18125  }
18126 // save ConstructRoute PrefDirVector
18127  Utilities->SaveFileString(ErrorFile, "***ConstructRoute PrefDirVector***");
18128  ConstructRoute->SavePrefDirVector(4, ErrorFile);
18129 // save ConstructRoute SearchVector
18130  Utilities->SaveFileString(ErrorFile, "***ConstructRoute SearchVector***");
18131  ConstructRoute->SaveSearchVector(1, ErrorFile);
18132 // save AllRoutes
18133  Utilities->SaveFileString(ErrorFile, "***Routes***");
18134  AllRoutes->SaveRoutes(1, ErrorFile);
18135 // save LockedRoutes
18136  Utilities->SaveFileString(ErrorFile, "***Locked routes***");
18138 // save ContinuationAutoSigEntries
18139  Utilities->SaveFileString(ErrorFile, "***ContinuationAutoSigEntries***");
18141 // save BarriersDownVector
18142  Utilities->SaveFileString(ErrorFile, "***BarriersDownVector***");
18143  Track->SaveSessionBarriersDownVector(1, ErrorFile);
18144 // save ChangingLCVector
18145  Utilities->SaveFileString(ErrorFile, "***ChangingLCVector***");
18146  Track->SaveChangingLCVector(0, ErrorFile);
18147 // save loaded timetable
18148  if(TimetableTitle == "")
18149  Utilities->SaveFileString(ErrorFile, "***No timetable loaded***");
18150  else
18151  {
18152  Utilities->SaveFileString(ErrorFile, "***Timetable***");
18153  if(!(SaveTimetableToSessionFile(1, ErrorFile, ErrorFileStr)))
18154  {
18155  Utilities->SaveFileString(ErrorFile, "***Loaded timetable failed to save***");
18156  }
18157  }
18158 // save editing timetable
18159  if(CreateEditTTTitle == "")
18160  Utilities->SaveFileString(ErrorFile, "***No editing timetable***");
18161  else
18162  {
18163  Utilities->SaveFileString(ErrorFile, "***Editing timetable - " + CreateEditTTTitle + "***");
18164  if(!(SaveTimetableToErrorFile(1, ErrorFile, ErrorFileStr, CreateEditTTFileName)))
18165  {
18166  Utilities->SaveFileString(ErrorFile, "***Editing timetable failed to save***");
18167  }
18168  }
18169 // save TimetableClock
18170  Utilities->SaveFileString(ErrorFile, "***TimetableClock***");
18171  Utilities->SaveFileDouble(ErrorFile, double(TrainController->TTClockTime));
18172 // save trains
18173  Utilities->SaveFileString(ErrorFile, "***Trains***");
18174  TrainController->SaveSessionTrains(1, ErrorFile);
18175 // save performance file
18176  Utilities->SaveFileString(ErrorFile, "***Performance file***");
18177  SavePerformanceFile(1, ErrorFile);
18178  Utilities->SaveFileString(ErrorFile, "***End of performance file***");
18179 // addition at v2.4.1 to save TrainController->AvHoursIntValue + any future additions
18180  Utilities->SaveFileString(ErrorFile, "***Additions after v2.3.1***");
18183  Utilities->SaveFileString(ErrorFile, "***Failed Trains***");
18184  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
18185  {
18187  {
18190  }
18191  }
18192  Utilities->SaveFileInt(ErrorFile, -1); // marker for end of failed trains
18193  Utilities->SaveFileString(ErrorFile, "End of file at v2.4.1");
18194 // end of v2.4.1 addition
18195 
18196  ErrorFile.close();
18197  }
18198  else
18199  {
18200  TrainController->StopTTClockMessage(6, "Error file failed to open, error log won't be saved.");
18201  }
18202  Screen->Cursor = TCursor(-2); // Arrow
18203 }
18204 
18205 // ---------------------------------------------------------------------------
18206 
18207 void TInterface::SaveTempTimetableFile(int Caller, AnsiString InFileName)
18208  // the .ttb section is delimited by '\n' followed by "***End***"
18209  // first create a .ttb file in the working folder exactly like the original
18210 
18211  // Note: this type of file use failed when used to resave timetable.tmp from temp .ttb file, but changed that to avoid so many rapid
18212  // file actions in quick succession & been OK since then, but nevertheless keep the 10 retries before giving message to be on safe side
18213 {
18214  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTempTimetableFile");
18215  if((TempTTFileName != "") && FileExists(TempTTFileName))
18216  {
18217  DeleteFile(TempTTFileName);
18218  }
18219  int TempTTFileNumber = 0;
18220 
18221  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
18222  {
18223  TempTTFileNumber++;
18224  }
18225  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
18226  int InHandle = FileOpen(InFileName, fmOpenRead);
18227  int Count = 0;
18228 
18229  while(InHandle < 0) // sometimes fails, have 10 retries before giving message
18230  {
18231  InHandle = FileOpen(InFileName, fmOpenRead);
18232  Count++;
18233  Delay(2, 50); // 50mSec delay between tries
18234  if(Count > 10)
18235  {
18236  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
18237  Utilities->CallLogPop(1400);
18238  return;
18239  }
18240  }
18241  int OutHandle = FileCreate(TempTTFileName);
18242 
18243  Count = 0;
18244  while(OutHandle < 0) // sometimes fails, have 10 retries before giving message
18245  {
18246  OutHandle = FileCreate(TempTTFileName);
18247  Count++;
18248  Delay(3, 50); // 50mSec delay between tries
18249  if(Count > 10)
18250  {
18251  ShowMessage("Failed to save temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
18252  FileClose(InHandle);
18253  Utilities->CallLogPop(1401);
18254  return;
18255  }
18256  }
18257  int CountIn, CountOut;
18258  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
18259 
18260  while(true)
18261  {
18262  CountIn = FileRead(InHandle, Buffer, 10000);
18263  CountOut = FileWrite(OutHandle, Buffer, CountIn);
18264  if(CountOut != CountIn)
18265  {
18266  ShowMessage("Error in writing to the temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
18267  delete Buffer;
18268  FileClose(InHandle);
18269  FileClose(OutHandle);
18270  Utilities->CallLogPop(1402);
18271  return;
18272  }
18273  if(CountIn < 10000)
18274  break;
18275  }
18276  delete Buffer;
18277  FileClose(InHandle);
18278  FileClose(OutHandle);
18279  Utilities->CallLogPop(1403);
18280 }
18281 
18282 // ---------------------------------------------------------------------------
18283 
18284 void TInterface::SetTrackLengths(int Caller, int Distance, int SpeedLimit) // Distance & SpeedLimit are -1 for no change to that parameter
18285 /*
18286  Rules: Platforms are fixed length elements of 100m and aren't changed - no, see note below. Variable length elements can't be less than 20m.
18287  above changed in v2.4.0 to be variable as other track, but if <50m or >200m a warning is given
18288 
18289  Enter with DistanceVector containing the PrefDir to be set, Distance containing the required sum of all element lengths,
18290  and SpeedLimit containing the speed limit. If either of these is -1 (can be -1 separately) then no change is to be made to it.
18291  Return for an empty DistanceVector. Deal first with a single element in the vector, giving a message if there is a platform there.
18292  Now set exit link position (XLinkPos) value for the first element in DistanceVector by checking which link connects to the second
18293  element in the vector, and give a warning message if fail to find it. Now have to make two passes through the vector, firstly to
18294  sum the fixed lengths, count the number of variable length elements and set the speed limit, and secondly to set the lengths.
18295  Firstly store the first XLinkPos so don't have to recalculate it for the second pass. On the first pass examine each element,
18296  incrementing the variable element count or summing the fixed length count as go along, and setting the speed limits providing
18297  SpeedLimit isn't -1. If Distance was -1 then still go through but don't count anything, just set the speed limits. Recalculate
18298  the next XLinkPos for each succeeding element.
18299  After the first pass return if Distance was -1 as in that case have now finished. Otherwise check if the distance to be set is less than
18300  the minimum possible within the rules, and if so give a message and return. Also give a warning message if there aren't any variable length
18301  elements. Now enter the second pass. In this the length of each variable element is set to int(RemainingDistance/RemainingVarElements) and
18302  fixed length elements are ignored. After each variable length element is set the RemainingDistance and RemainingVarElements are recalculated
18303  ready for the next setting. In this way there is never more than 1 difference between any two variable length elements and the total
18304  distance sums exactly to the value required. A check is made after every variable length element has been set to see whether RemainingDistance
18305  and RemainingVarElements are zero, and if they don't reach zero together (which they should after the last variable length element has
18306  been set), an error message is given.
18307 */
18308 
18309 {
18310  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLengths," + AnsiString(Distance) + "," + AnsiString(SpeedLimit));
18311  bool FoundFlag;
18312 
18313 // ResetDistanceElements(4);
18314  if(ConstructPrefDir->PrefDirSize() == 0)
18315  {
18316  Utilities->CallLogPop(608);
18317  return;
18318  }
18319 // must have PrefDir size of at least 2
18320 
18321 // first pass to count number of variable length elements, sum fixed lengths & set speed limit
18322 // for version in v2.4.0 have no fixed length elements but leave code as is as much as possible
18323  int VarElements = 0; // FixedLength = 0; drop this in v2.4.0
18324  bool NamedLocPresent = false;
18325 
18326  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
18327  {
18328  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(167, x);
18329  TTrackElement & TE = Track->TrackElementAt(34, Track->GetVectorPositionFromTrackMap(28, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
18330  if(!FoundFlag)
18331  {
18332  throw Exception("Error - failed to find track element at " + AnsiString(TE.HLoc) + " & " + AnsiString(TE.VLoc) + " in SetLengths");
18333  }
18334  if((Distance != -1) && (!Track->IsPlatformOrNamedNonStationLocationPresent(2, TE.HLoc, TE.VLoc)))
18335  VarElements++;
18336  else if((Distance != -1) && (Track->IsPlatformOrNamedNonStationLocationPresent(3, TE.HLoc, TE.VLoc)))
18337  {
18338  VarElements++; // added in v2.4.0 for no fixed elements
18339  NamedLocPresent = true;
18340 // FixedLength+= DefaultTrackLength; dropped in v2.4.0 for no fixed elements
18341  }
18342 
18343  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be points
18344  {
18345  if(SpeedLimit != -1)
18346  TE.SpeedLimit01 = SpeedLimit;
18347  }
18348  else
18349  {
18350  if(SpeedLimit != -1)
18351  TE.SpeedLimit23 = SpeedLimit;
18352  }
18353  }
18354  if(Distance == -1) // can't return before this as need to set speed limits
18355  {
18356  Utilities->CallLogPop(612);
18357  return;
18358  }
18359 
18360  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) < 50)) // these two additions are for in v2.4.0
18361  {
18362  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might depart too far from reality.");
18363  }
18364 
18365  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) > 200))
18366  {
18367  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might depart too far from reality.");
18368  }
18369 
18370 /* if(NamedLocPresent) as was
18371  {
18372  ShowMessage("Named location lengths won't be changed");
18373  }
18374 */
18375 
18376  if((VarElements * 20) > Distance) // removed '+ FixedLength'
18377  {
18378  ShowMessage("Required distance is less than the minimum, will set each element to the minimum (20m)");
18379  Distance = (VarElements * 20); // removed '+ FixedLength'
18380  }
18381  if(VarElements == 0)
18382  {
18383 // ShowMessage("Unable to set distance as all elements are of fixed length"); as was
18384  ShowMessage("No elements selected"); // probably don't need this but include for safety
18385  Utilities->CallLogPop(613);
18386  return;
18387  }
18388 
18389 // second pass, set variable lengths
18390  int RemainingDistance = Distance, RemainingVarElements = VarElements, NextLength = RemainingDistance / VarElements; // removed ' - FixedLength'
18391 
18392  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
18393  {
18394  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(168, x);
18395  TTrackElement & TE = Track->TrackElementAt(35, Track->GetVectorPositionFromTrackMap(29, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
18396 // if(!Track->IsPlatformOrNamedNonStationLocationPresent(4, TE.HLoc, TE.VLoc)) //variable lengths dropped in v2.4.0
18397 // {
18398  if(NextLength < 20)
18399  NextLength = 20; // added for safety
18400  if(TE.TrackType == Points)
18401  {
18402  if((PrefDirElement.GetELinkPos() == 1) || (PrefDirElement.GetXLinkPos() == 1))
18403  {
18404  TE.Length01 = NextLength;
18405  }
18406  else
18407  {
18408  TE.Length23 = NextLength;
18409  }
18410  }
18411  else
18412  {
18413  if(PrefDirElement.GetELinkPos() < 2)
18414  {
18415  TE.Length01 = NextLength;
18416  }
18417  else
18418  {
18419  TE.Length23 = NextLength;
18420  }
18421  }
18422  RemainingDistance -= NextLength;
18423  RemainingVarElements--;
18424  if(RemainingVarElements > 0)
18425  NextLength = RemainingDistance / RemainingVarElements;
18426  else
18427  NextLength = 20;
18428 
18429 /* removed these as using integer division & that sometimes problematic. None of these errors ever reported but be safe
18430  if((RemainingDistance == 0) && (RemainingVarElements != 0))
18431  {
18432  throw Exception("Error RemainingDistance == 0 & RemainingVarElements != 0");
18433  }
18434  if((RemainingDistance != 0) && (RemainingVarElements == 0))
18435  {
18436  throw Exception("Error RemainingDistance != 0 & RemainingVarElements == 0");
18437  }
18438 */
18439 // }
18440  }
18441  Utilities->CallLogPop(614);
18442 }
18443 
18444 // ---------------------------------------------------------------------------
18445 
18447 {
18448  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveAsSubroutine");
18450  ShowMessage("Nothing to save!");
18451  else
18452  {
18453  if(Track->IsReadyForOperation(false))
18454  {
18455  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly";
18456  }
18457  else
18458  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev";
18459  if(SaveRailwayDialog->Execute())
18460  {
18461  if(SaveRailwayDialog->InitialDir != TPath::GetDirectoryName(SaveRailwayDialog->FileName))//new at v2.6.0 to retain a new directory
18462  {
18463  SaveRailwayDialog->InitialDir = TPath::GetDirectoryName(SaveRailwayDialog->FileName);
18464  LoadRailwayDialog->InitialDir = TPath::GetDirectoryName(SaveRailwayDialog->FileName);
18465  }
18466  Screen->Cursor = TCursor(-11); // Hourglass;
18467  TrainController->LogEvent("Save " + SaveRailwayDialog->FileName);
18468  AnsiString Extension = "";
18469  if(SaveRailwayDialog->FileName.Length() > 2)
18470  {
18471  Extension = AnsiString(SaveRailwayDialog->FileName).SubString(AnsiString(SaveRailwayDialog->FileName).Length() - 2, 3).UpperCase();
18472  }
18473  if((Extension == "DEV") || (Track->IsReadyForOperation(true) && (Extension == "RLY"))) //give duplicated location name message if appropriate
18474  {
18475  std::ofstream VecFile(AnsiString(SaveRailwayDialog->FileName).c_str());
18476  if(!(VecFile.fail()))
18477  {
18481  // save track elements
18482  if(Track->UserGraphicVector.empty())
18483  {
18484  Track->SaveTrack(1, VecFile, false); // false for no graphics (**Active elements** saved as marker)
18485  }
18486  else
18487  {
18488  Track->SaveTrack(13, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
18489  }
18490  // save text elements
18491  TextHandler->SaveText(1, VecFile);
18492  // save PrefDir elements
18493  EveryPrefDir->SavePrefDirVector(1, VecFile);
18494  if(!Track->UserGraphicVector.empty())
18495  {
18496  // save user graphics
18497  Track->SaveUserGraphics(4, VecFile);
18498  }
18499  VecFile.close();
18500  SavedFileName = SaveRailwayDialog->FileName; // includes the full PrefDir
18501  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
18502  {
18503  char LastChar = SavedFileName[SavedFileName.Length()];
18504  if((LastChar == 'y') || (LastChar == 'Y'))
18505  {
18506  RlyFile = true;
18507  }
18508  else
18509  {
18510  RlyFile = false;
18511  }
18512  }
18513  else
18514  {
18515  RlyFile = false;
18516  }
18517  FileChangedFlag = false;
18518  for(int x = SaveRailwayDialog->FileName.Length(); x > 0; x--)
18519  {
18520  if(SaveRailwayDialog->FileName[x] == '\\')
18521  {
18522  RailwayTitle = SaveRailwayDialog->FileName.SubString(x + 1, SaveRailwayDialog->FileName.Length() - x - 4);
18523  // TimetableTitle = ""; leave this as is, no need to unload a tt just because saved railway
18524  SetCaption(7);
18525  break;
18526  }
18527  }
18528  Level1Mode = BaseMode;
18529  SetLevel1Mode(13); // to disable the save option
18530  } // if(!(VecFile.fail()))
18531  else
18532  ShowMessage("File open failed prior to save");
18533  } // else following if(!Track->IsReadyForOperation() && (Extension != "DEV"))
18534  else
18535  {
18536  ShowMessage("Can't save: extension must be either '.dev', or '.rly' with railway ready for operation");
18537  }
18538  Screen->Cursor = TCursor(-2); // Arrow
18539  } //if(SaveRailwayDialog->Execute())
18540  }
18541  Utilities->CallLogPop(1546);
18542 }
18543 
18544 // ---------------------------------------------------------------------------
18545 
18547 { // no need for caller or log as only setting values
18548  CutMenuItem->Visible = true;
18549  CopyMenuItem->Visible = true;
18550  FlipMenuItem->Visible = true;
18551  MirrorMenuItem->Visible = true;
18552  RotRightMenuItem->Visible = true;
18553  RotLeftMenuItem->Visible = true;
18554  RotateMenuItem->Visible = true;
18555  PasteMenuItem->Visible = true;
18556 // PasteWithAttributesMenuItem->Visible = true; //added at v2.2.0
18557  DeleteMenuItem->Visible = true;
18558  SelectLengthsMenuItem->Visible = true;
18559  ReselectMenuItem->Visible = true;
18560 
18561  CutMenuItem->Enabled = false;
18562  CopyMenuItem->Enabled = false;
18563  FlipMenuItem->Enabled = false;
18564  MirrorMenuItem->Enabled = false;
18565  RotRightMenuItem->Enabled = false;
18566  RotLeftMenuItem->Enabled = false;
18567  RotateMenuItem->Enabled = false;
18568  PasteMenuItem->Enabled = false;
18569 // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0
18570  DeleteMenuItem->Enabled = false;
18571  SelectLengthsMenuItem->Enabled = false;
18572  if(SelectionValid)
18573  ReselectMenuItem->Enabled = true;
18574  else
18575  ReselectMenuItem->Enabled = false;
18576 
18577  SelectBiDirPrefDirsMenuItem->Visible = false;
18578  CancelSelectionMenuItem->Enabled = true;
18579  SelectMenuItem->Enabled = true;
18580 
18581  if(NoRailway())
18582  {
18583  EditMenu->Enabled = false;
18584  }
18585  else
18586  EditMenu->Enabled = true;
18587 }
18588 
18589 // ---------------------------------------------------------------------------
18590 
18592 { // no need for caller or log as only setting values
18593  EditMenu->Enabled = true;
18594 
18595  CutMenuItem->Visible = false;
18596  CopyMenuItem->Visible = false;
18597  FlipMenuItem->Visible = false;
18598  MirrorMenuItem->Visible = false;
18599  RotRightMenuItem->Visible = false;
18600  RotLeftMenuItem->Visible = false;
18601  RotateMenuItem->Visible = false;
18602  PasteMenuItem->Visible = false;
18603 // PasteWithAttributesMenuItem->Visible = false; //added at v2.2.0
18604  DeleteMenuItem->Visible = false;
18605  SelectLengthsMenuItem->Visible = false;
18606  ReselectMenuItem->Visible = false;
18607 
18608  SelectBiDirPrefDirsMenuItem->Visible = true;
18609  SelectBiDirPrefDirsMenuItem->Enabled = false;
18610  CancelSelectionMenuItem->Enabled = true;
18611  SelectMenuItem->Enabled = true;
18612 }
18613 
18614 // ---------------------------------------------------------------------------
18615 
18617 {
18618  return ((Track->NoActiveOrInactiveTrack(5)) && (TextHandler->TextVectorSize(8) == 0) && Track->UserGraphicVector.empty());
18619 }
18620 
18621 // ---------------------------------------------------------------------------
18622 
18624 {
18625  SelectRect.left = 0;
18626  SelectRect.right = 0;
18627  SelectRect.top = 0;
18628  SelectRect.bottom = 0;
18629 }
18630 
18631 // ---------------------------------------------------------------------------
18632 
18633 bool TInterface::EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
18634 { // return position of erased name in HPos & VPos, return true for found & erased
18635  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationNameText," + Name);
18636  bool TextFound = false;
18637 
18638 // if(Track->LocationNameMultiMap.find(Name) == Track->LocationNameMultiMap.end()) {} //name not in LocationNameMultiMap, so don't erase from TextVector //condition dropped at v1.1.4 because of change in EnterLocationNames
18639 /* else */ if(TextHandler->FindText(0, Name, HPos, VPos))
18640  {
18641  if(TextHandler->TextErase(4, HPos, VPos, Name))
18642  {;
18643  } // condition not used
18644  TextFound = true;
18645  }
18646  Utilities->CallLogPop(1956);
18647  return TextFound;
18648 }
18649 
18650 // ---------------------------------------------------------------------------
18651 
18652 void TInterface::AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
18653 {
18654  if(Name == "")
18655  {
18656  return;
18657  }
18658  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddLocationNameText," + Name + "," + AnsiString(HPos) + "," +
18659  AnsiString(VPos) + "," + AnsiString((short)UseEnteredPosition));
18660  int VPosHi, VPosLo, TextPosHi, TextPosLo;
18661  TFont *Font = Display->GetFont();
18662 
18663  if(!UseEnteredPosition)
18664  {
18665  if(!Track->FindHighestLowestAndLeftmostNamedElements(0, Name, VPosHi, VPosLo, HPos))
18666  {
18667  Utilities->CallLogPop(1561);
18668  return;
18669  }
18670  int Depth = abs(Font->Height); // Height may be negative - see C++Builder Help file
18671  TextPosHi = VPosHi + 20; // add depth of track element + 4 pixels
18672  TextPosLo = VPosLo - Depth - 4; // reduce by depth of font + 4 pixels
18673  int ScreenPosHi = (Display->DisplayOffsetV * 16) + 576;
18674  int ScreenPosLo = Display->DisplayOffsetV * 16;
18675  if(TextPosLo >= ScreenPosLo)
18676  VPos = TextPosLo; // if Lo value on screen then use that - displays above the location
18677  else if(TextPosHi < ScreenPosHi)
18678  VPos = TextPosHi;
18679  else
18680  VPos = ScreenPosLo + 288; // if location extends to or beyond height of screen the display in centre of screen
18681  }
18682  TTextItem TI(HPos, VPos, Name, Font);
18683 
18684  TI.Font = Font; // may have been changed in constructor when returned as reference
18685  TextHandler->EnterAndDisplayNewText(1, TI, HPos, VPos);
18686  Utilities->CallLogPop(1558);
18687 }
18688 
18689 // ---------------------------------------------------------------------------
18690 
18692 {
18693  try
18694  {
18695 /*
18696  ShowMessage(
18697  "Interface->Left + Interface->Width " + UnicodeString(Interface->Left + Interface->Width) +
18698  "\nInterface->Left + MainScreen->Left + MainScreen->Width " +
18699  UnicodeString(Interface->Left + MainScreen->Left + MainScreen->Width) +
18700  "\n\nMainScreen->Width " + UnicodeString(MainScreen->Width) +
18701  "\nMainScreen->Height " + UnicodeString(MainScreen->Height) +
18702  "\nMainScreen->Top " + UnicodeString(MainScreen->Top) +
18703  "\nMainScreen->Left " + UnicodeString(MainScreen->Left) +
18704  " Right " + UnicodeString(MainScreen->Width + MainScreen->Left) +
18705  "\n\nInterface->Width " + UnicodeString(Interface->Width) +
18706  "\nInterface->Left " + UnicodeString(Interface->Left) +
18707  "\nInterface->Top " + UnicodeString(Interface->Top) +
18708  "\n\nScreenRightButton->Left " + UnicodeString(ScreenRightButton->Left)
18709  );
18710 */
18711 /*
18712  for(unsigned int x=0; x<TrainController->TrainVector.size(); x++)
18713  {
18714  if((TrainController->TrainVectorAt(-1, x).HeadCode == "2K02") && (!TrainController->TrainVectorAt(-1, x).TrainOnContinuation(-1)))
18715  {
18716  TrainController->TrainVectorAt(-1, x).TrainFailurePending = true;
18717  }
18718  }
18719 */
18720 
18721 // throw Exception("Test error"); //generate an error file
18722 
18723 // ShowMessage("MissedTicks = " + AnsiString(MissedTicks) + "; TotalTicks = " + AnsiString(TotalTicks));
18724 
18725  }
18726  catch(const Exception &e)
18727  {
18728  ErrorLog(114, e.Message);
18729  }
18730 }
18731 
18732 // ---------------------------------------------------------------------------
18733 /*
18734  void TInterface::LoadNormalSignalGlyphs(int Caller) //changed - see below
18735  {
18736  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
18737  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68"); SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
18738  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70"); SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
18739  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
18740  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74"); SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
18741  Utilities->CallLogPop(**);
18742  }
18743 
18744  //---------------------------------------------------------------------------
18745 
18746  void TInterface::LoadGroundSignalGlyphs(int Caller) //changed - see below
18747  {
18748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
18749  SpeedButton68->Glyph->LoadFromResourceName(0, "bm68grounddblred"); SpeedButton69->Glyph->LoadFromResourceName(0, "bm69grounddblred");
18750  SpeedButton70->Glyph->LoadFromResourceName(0, "bm70grounddblred"); SpeedButton71->Glyph->LoadFromResourceName(0, "bm71grounddblred");
18751  SpeedButton72->Glyph->LoadFromResourceName(0, "bm72grounddblred"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73grounddblred");
18752  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74grounddblred"); SpeedButton75->Glyph->LoadFromResourceName(0, "bm75grounddblred");
18753  Utilities->CallLogPop(**);
18754  }
18755 */
18756 // ---------------------------------------------------------------------------
18757 void TInterface::LoadNormalSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
18758 {
18759  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
18768  Utilities->CallLogPop(1871);
18769 }
18770 
18771 // ---------------------------------------------------------------------------
18772 
18773 void TInterface::LoadGroundSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
18774 {
18775  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
18784  Utilities->CallLogPop(1872);
18785 }
18786 
18787 // ---------------------------------------------------------------------------
18788 
18789 void TInterface::UpdateOperatorActionPanel(int Caller) // new at v2.2.0
18790  // limit it to 20 entries max
18791 {
18792  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UpdateOperatorActionPanel");
18794  {
18795  OAListBox->Clear();
18796  }
18798  // new at v2.2.0
18799  {
18800  Utilities->CallLogPop(2092);
18801  return;
18802  }
18803  AnsiString OpTimeToActDisplay;
18804  AnsiString OpTimeToActString;
18805  AnsiString HeadCode;
18806  float OpTimeToActFloat;
18807  TTrainController::THCandTrainPosParam HCandTrainPosParam;
18808 
18811  {
18812  if(OAListBox->Items->Count >= 20)
18813  {
18814  break;
18815  }
18816  OpTimeToActFloat = TrainController->OpTimeToActMultiMapIterator->first;
18817  HCandTrainPosParam = TrainController->OpTimeToActMultiMapIterator->second;
18818  HeadCode = HCandTrainPosParam.first;
18819  if(OpTimeToActFloat < 0.25) // 15 secs estimated
18820  {
18821  OpTimeToActString = "NOW";
18822  }
18823  else if(OpTimeToActFloat < 1)
18824  {
18825  OpTimeToActString = "<1";
18826  }
18827  else
18828  {
18829  OpTimeToActString = AnsiString(floor(OpTimeToActFloat));
18830  }
18831  if(OpTimeToActFloat < 60)
18832  {
18833  OpTimeToActDisplay = HeadCode + AnsiString('\t') + OpTimeToActString;
18834  OAListBox->Items->Add(OpTimeToActDisplay); // original
18835  }
18837  }
18838  Utilities->CallLogPop(2093);
18839 }
18840 
18841 // ---------------------------------------------------------------------------
18842 
18843 void TInterface::LoadUserGraphic(int Caller) // new at v2.4.0
18844 {
18845  try
18846  {
18847  TrainController->LogEvent("LoadUserGraphic");
18848  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadUserGraphic");
18849  if(LoadUserGraphicDialog->Execute())
18850  {
18851  TrainController->LogEvent("LoadUserGraphic " + LoadUserGraphicDialog->FileName);
18852  SelectedGraphicFileName = AnsiString(LoadUserGraphicDialog->FileName); // SelectedGraphicFileName is a class member
18854  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
18855  if(UGMIt == Track->UserGraphicMap.end()) // i.e. there isn't an entry for that filename so insert one, else take no action
18856  {
18857  UGME.first = SelectedGraphicFileName;
18858  TPicture *PicPtr = new TPicture;
18859  PicPtr->LoadFromFile(SelectedGraphicFileName);
18860  UGME.second = PicPtr;
18861  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
18862  {
18863  throw Exception("Map Insertion Error 1 - UserGraphicMap insertion failure for " + SelectedGraphicFileName);
18864  }
18865  }
18867  SetLevel2TrackMode(65);
18868  }
18869  Utilities->CallLogPop(2191);
18870  }
18871  catch(const EInvalidGraphic &e)
18872  {
18873  ShowMessage(
18874  "Incorrect file format, the file can't be loaded.\nEnsure that the file you want is a valid graphic file with extension .bmp, .gif, .jpg, or .png");
18875  }
18876  catch(const Exception &e)
18877  {
18878  ErrorLog(215, e.Message);
18879  }
18880 }
18881 
18882 // ---------------------------------------------------------------------------
18883 /*
18884  Problems with ifstream reading (see 'SessionFileIntegrityCheck(AnsiString FileName)' above):-
18885 
18886  These problems were with Borland C++Builder 4.
18887 
18888  The functions saved in OldFiles\Backups220809Duringifstream testing were used for testing the odd behaviour where the
18889  ifstream pointer gave different characters using get() and getline(), when reading the timetable entries in the session
18890  file for 20/08/09 at 18:45 (saved). All was well until point 48677 in the session file, when for some reason the
18891  getline(0 & get(0 gave different results. Many earlier timetable strings had been read OK before that, and it wasn't
18892  clear what was special about this particular string.
18893  Later more detailed study found that on reading the string beginning at point 48605 (i.e. the one earlier than above),
18894  within function CheckNoNewLineAtStartNonZeroTerminatedFileString the file pointer (using tellg()) reduced from 48606 to
18895  48604 after reading the 'F' character. Thereafter characters were read correctly but the pointer remained 2 too low.
18896  This is thought to be a flaw in the compiler.
18897  Later again additional tellg()s and a seekg()s were included in CheckNoNewLineAtStartNonZeroTerminatedFileString, and
18898  though these should have had no effect they somehow caused the next getline() within CheckTimetableFromSessionFile to
18899  read a null, even though the pointer had been reset to its value before the call to
18900  CheckNoNewLineAtStartNonZeroTerminatedFileString. Again this seems to be a flaw in the compiler, where the pointer
18901  that is indicated by tellg and the true pointer within the system can be different.
18902  Tried the old c++ stream library to see if that worked but it was exactly the same. Probably because the same code is
18903  used for both with the new library just defined within the std namespace.
18904  Success!! Traced to the putback function failing. It (apparently) can't be used if the file pointer has been altered
18905  after the last read that is to be put back. Corrected that & the most recent session file checked out & loaded OK.
18906  (note - don't need the ifstream file to be open in output mode for the putback to work)
18907  But: the earlier file - 18:45 as above - still fails to advance the file pointer in the middle of checking the
18908  timetable, it sticks at position 48601. This position points to 'r' in 'Frh' just before a newline. Also the file
18909  integrity is OK up to and after this sticking point. Oddly though the loading function works fine (i.e. by bypassing
18910  the integrity check function), though the timetable isn't read directly, it is copied to a new stand-alone timetable
18911  file and that read by the program.
18912  Created a new version of CheckNoNewLineAtStartNonZeroTerminatedFileString with 'New' at end, & got rid of all the
18913  internal digressions & getlines. This passed the earlier sticking point, but stuck later at 48677, i.e. the 'h' from
18914  'Frh' at the end of the entry following that for the earlier sticking point. Here
18915  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew works fine, with end pointer correctly set at 48680, i.e. after the
18916  newline, but the subsequent getline() function, although it retrieves the line correctly, the file pointer is set to
18917  48677, i.e. before the newline, so getline seems to fail to extract the newline character. Still to check - why doesn't
18918  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew see 'h' instead of '0' in the subsequent read? If it did the two
18919  would tally, though would still be wrong.
18920  Further investigation:- CheckNoNewLineAtStartNonZeroTerminatedFileStringNew doesn't seem to recognize the file pointer
18921  as set by seekg at 48677. It continues to read at the point it left off earlier, whereas getline() does read at 48677
18922  & recovers 'h'. Continuing to apply getline() after the above effect it is found that it doesn't extract newlines after
18923  reading further lines, but extracts them when read alone i.e. it reads a line then a null in succession, although the
18924  lines are only separated by single newline characters.
18925 
18926  Need to check:
18927  1. Does the file read correctly if only get() functions used without getline() and without resetting the file pointer?
18928  2. Does the file read correctly if only getline() functions used without get() and without resetting the file pointer?
18929  3. Does the file read correctly if get() functions alternated with getline() but without resetting the file pointer?
18930 
18931  For 1: Still goes wrong at usual place, reads 'h' at the same point. Try not resetting the file pointer with seekg.
18932  Tried this - got past the earlier point but failed later with a reduction in file pointer after a character read. In
18933  fact the reduction was by 40 bytes for reading a single comma! Try without any tellg's - yes, that got past all the
18934  timetable OK. So, works OK with just get() providing no tellg's (& no seekg's).
18935 
18936  For 2: Works OK using getline().
18937 
18938  For 3: Gets to end of timetable OK but the next tellg gives a wrong value. Check if using getline() alone gives a
18939  wrong tellg. Tried getline() alone, reached end of TT as before, but gave the same wrong file pos on using tellg.
18940  Try continuing to see if works OK in spite of tellg giving wrong result. Yes it works OK. Hence the problem seems to
18941  be tellg, which sometimes returns wrong results, and they corrupt things when used in seekg.
18942 
18943  Overall conclusion: Avoid all tellg's & seekg's. If need to reset a file position then close and reopen it.
18944 */
18945 
18946 // ---------------------------------------------------------------------------
18947 
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:16162
TInterface::SpeedButton59
TSpeedButton * SpeedButton59
Definition: InterfaceUnit.h:563
TInterface::CopyTTEntryButtonClick
void __fastcall CopyTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3666
TInterface::CtrlKey
bool CtrlKey
true when the CTRL key is pressed (see also ShiftKey)
Definition: InterfaceUnit.h:937
TInterface::MTBFEditBox
TEdit * MTBFEditBox
Definition: InterfaceUnit.h:481
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:10377
TInterface::ScreenLeftButtonClick
void __fastcall ScreenLeftButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8476
TInterface::ExitMenuItem
TMenuItem * ExitMenuItem
Definition: InterfaceUnit.h:417
TTrain::AllowedToPassRedSignal
bool AllowedToPassRedSignal
set when train has been called on, or when under signaller control and instructed to pass a red signa...
Definition: TrainUnit.h:339
TInterface::TextMoveVPos
int TextMoveVPos
used to store the original text 'H' & 'V' positions for use during text moving
Definition: InterfaceUnit.h:1104
TInterface::OperMode
@ OperMode
Definition: InterfaceUnit.h:855
TTrain::ZeroPowerNoNewShuttleFromNonRepeatMessage
bool ZeroPowerNoNewShuttleFromNonRepeatMessage
Definition: TrainUnit.h:306
TInterface::SpeedButton140
TSpeedButton * SpeedButton140
Definition: InterfaceUnit.h:644
TTrain::ZeroPowerNoNewServiceMessage
bool ZeroPowerNoNewServiceMessage
Definition: TrainUnit.h:305
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:10350
TInterface::AddPrefDirButton
TBitBtn * AddPrefDirButton
Definition: InterfaceUnit.h:116
TInterface::RemoveTrainMenuItem
TMenuItem * RemoveTrainMenuItem
Definition: InterfaceUnit.h:467
TInterface::LocationNamesSetImage
TImage * LocationNamesSetImage
Definition: InterfaceUnit.h:278
TInterface::SpeedLimitBox
TEdit * SpeedLimitBox
distance/speed setting edit box that accepts speed limits
Definition: InterfaceUnit.h:92
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TInterface::SaveImageAndGridMenuItemClick
void __fastcall SaveImageAndGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2644
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TTrainController
Handles all train and timetable activities, only one object created.
Definition: TrainUnit.h:635
TInterface::FloatingInfoMenu
TMenuItem * FloatingInfoMenu
Definition: InterfaceUnit.h:443
TInterface::SpeedButton34
TSpeedButton * SpeedButton34
Definition: InterfaceUnit.h:538
TInterface::NewTTEntryKeyFlag
bool NewTTEntryKeyFlag
Definition: InterfaceUnit.h:1026
TInterface::ConflictAnalysisButtonClick
void __fastcall ConflictAnalysisButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12469
TInterface::CallingOnButton
TSpeedButton * CallingOnButton
Definition: InterfaceUnit.h:205
TInterface::BuildTrainDataVectorForValidateFile
bool BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
Check the integrity of a stored timetable file (either as a stand alone file or within a session file...
Definition: InterfaceUnit.cpp:17240
TInterface::SpeedButton42
TSpeedButton * SpeedButton42
Definition: InterfaceUnit.h:546
TInterface::SelectBitmapMouseLocX
int SelectBitmapMouseLocX
when flag SelectPickedUp is set to true (see above - to allow a selected screen area to move during M...
Definition: InterfaceUnit.h:1080
TInterface::PrefDirPanel
TPanel * PrefDirPanel
'Set preferred directions' panel
Definition: InterfaceUnit.h:359
TInterface::PrefDirPanelLabel
TLabel * PrefDirPanelLabel
label to the left of PrefDirPanel
Definition: InterfaceUnit.h:305
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:11832
TInterface::MTBFEditBoxKeyUp
void __fastcall MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:12284
TInterface::TrackMode
@ TrackMode
Definition: InterfaceUnit.h:855
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1586
TInterface::SaveSessionButton
TBitBtn * SaveSessionButton
Definition: InterfaceUnit.h:201
TInterface::TTLabel2
TLabel * TTLabel2
Definition: InterfaceUnit.h:340
TInterface::TTClockx1ButtonClick
void __fastcall TTClockx1ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11888
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:182
TInterface::LengthConversionPanel
TPanel * LengthConversionPanel
Definition: InterfaceUnit.h:105
TInterface::SpeedButton143
TSpeedButton * SpeedButton143
Definition: InterfaceUnit.h:647
TInterface::ChangeDirectionMenuItem
TMenuItem * ChangeDirectionMenuItem
Definition: InterfaceUnit.h:462
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:6700
TTrain::MidEntryPos
int MidEntryPos
Definition: TrainUnit.h:327
TTrainController::RebuildOpTimeToActMultimap
void RebuildOpTimeToActMultimap(int Caller)
new v2.2.0 for OperatorActionPanel
Definition: TrainUnit.cpp:17432
TTrainController::PwrHigh
bool PwrHigh
Definition: TrainUnit.h:743
TInterface::StepForwardMenuItem
TMenuItem * StepForwardMenuItem
Definition: InterfaceUnit.h:465
TTrack::SelectGraphicVector
TUserGraphicVector SelectGraphicVector
Definition: TrackUnit.h:705
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:90
SignallerMoveForwards
@ SignallerMoveForwards
Definition: TrainUnit.h:50
TInterface::SignallerControlStopMenuItem
TMenuItem * SignallerControlStopMenuItem
Definition: InterfaceUnit.h:466
TRailGraphics::ConvertSignalsToOppositeHand
void ConvertSignalsToOppositeHand(int Caller)
Converts all signal graphics to opposite hand new at v2.3.0.
Definition: GraphicUnit.cpp:4307
TInterface::FormResize
void __fastcall FormResize(TObject *Sender)
Definition: InterfaceUnit.cpp:12138
TInterface::SpeedButton70
TSpeedButton * SpeedButton70
Definition: InterfaceUnit.h:574
TInterface::SpeedButton144
TSpeedButton * SpeedButton144
Definition: InterfaceUnit.h:648
TInterface::SpeedButton32
TSpeedButton * SpeedButton32
Definition: InterfaceUnit.h:536
TInterface::SaveTTAsButtonClick
void __fastcall SaveTTAsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4135
TInterface::SelectBitmapHLoc
int SelectBitmapHLoc
the original (prior to moving & after finished moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1078
TInterface::OperatorActionButton
TBitBtn * OperatorActionButton
Definition: InterfaceUnit.h:202
TInterface::DistanceKey
TImage * DistanceKey
information panel displayed when setting distances & speed limits
Definition: InterfaceUnit.h:268
AboutUnit.h
Arrive
@ Arrive
Definition: TrainUnit.h:49
TInterface::OperatorActionPanelDragStartX
int OperatorActionPanelDragStartX
mouse 'X' position when the OperatorActionPanel begins to be dragged
Definition: InterfaceUnit.h:1066
TInterface::SpeedButton54
TSpeedButton * SpeedButton54
Definition: InterfaceUnit.h:558
TInterface::PasteWarningSentFlag
bool PasteWarningSentFlag
indicates that the warning message about pasting overwriting the area has been given,...
Definition: InterfaceUnit.h:961
TInterface::StartWholeRailwayMoveVPos
int StartWholeRailwayMoveVPos
mouse Y position when start to move the whole railway
Definition: InterfaceUnit.h:1090
TTrain::ZeroPowerNoCDTMessage
bool ZeroPowerNoCDTMessage
Definition: TrainUnit.h:304
TTrain::CallingOnFlag
bool CallingOnFlag
calling on permitted
Definition: TrainUnit.h:345
TInterface::UnrestrictedButton
TBitBtn * UnrestrictedButton
Definition: InterfaceUnit.h:197
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:706
TRailGraphics::SpeedBut72NormBlackGlyph
Graphics::TBitmap * SpeedBut72NormBlackGlyph
Definition: GraphicUnit.h:1049
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:11872
TInterface::ExportTTMenuItemClick
void __fastcall ExportTTMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3051
TInterface::RestoreTTKeyFlag
bool RestoreTTKeyFlag
Definition: InterfaceUnit.h:1032
TInterface::CancelSelectionMenuItemClick
void __fastcall CancelSelectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9750
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3579
TInterface::PERFLOG_DIR_NAME
static const UnicodeString PERFLOG_DIR_NAME
Definition: InterfaceUnit.h:868
TInterface::WholeRailwayMoving
bool WholeRailwayMoving
true when moving the railway with the mouse, new at v2.1.0
Definition: InterfaceUnit.h:1011
TInterface::TextFoundFlag
bool TextFoundFlag
indicates that a text item has been found when clicking on a build screen during 'AddText' or 'MoveTe...
Definition: InterfaceUnit.h:991
TInterface::DisableRouteButtons
void DisableRouteButtons(int Caller)
Called during operation whenever the route type buttons need to be disabled, e.g. when paused.
Definition: InterfaceUnit.cpp:18001
TInterface::OperateRailwayMenuItemClick
void __fastcall OperateRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2014
TInterface::DerailImage
TImage * DerailImage
Definition: InterfaceUnit.h:264
TTrain::MaxRunningSpeed
double MaxRunningSpeed
the current maximum train running speed
Definition: TrainUnit.h:385
TInterface::TTLabel3
TLabel * TTLabel3
Definition: InterfaceUnit.h:341
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:689
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:289
TRailGraphics::SpeedBut75NormBlackGlyph
Graphics::TBitmap * SpeedBut75NormBlackGlyph
Definition: GraphicUnit.h:1052
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:6553
RestoreTimetableControl
@ RestoreTimetableControl
Definition: TrainUnit.h:50
TTrainController::LastSessionSaveTTClockTime
TDateTime LastSessionSaveTTClockTime
Definition: TrainUnit.h:646
TInterface::TTSelectedEntry
AnsiString TTSelectedEntry
used to record the current timetable entry when changing to AZ order or back to original order
Definition: InterfaceUnit.h:924
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TAllRoutes::AutoSigsRoute
@ AutoSigsRoute
Definition: TrackUnit.h:1516
TInterface::SpeedButton19
TSpeedButton * SpeedButton19
Definition: InterfaceUnit.h:523
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5066
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6465
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5093
TActionVectorEntry::LocationType
TTimetableLocationType LocationType
indicates where the train is when the relevant action occurs
Definition: TrainUnit.h:112
TInterface::MasterClockTimer
void __fastcall MasterClockTimer(TObject *Sender)
Definition: InterfaceUnit.cpp:7780
TTrack::GapFlashGreenPosition
int GapFlashGreenPosition
Definition: TrackUnit.h:673
TInterface::MainScreen
TImage * MainScreen
the railway display screen
Definition: InterfaceUnit.h:285
TInterface::SpeedButton67
TSpeedButton * SpeedButton67
Definition: InterfaceUnit.h:571
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:64
TInterface::CutMenuItem
TMenuItem * CutMenuItem
Definition: InterfaceUnit.h:432
TInterface::SpeedButton120
TSpeedButton * SpeedButton120
Definition: InterfaceUnit.h:624
TInterface::LCResetCounter
unsigned int LCResetCounter
count up to 20 then resets - to check LCs & raise barriers if no route & no train present
Definition: InterfaceUnit.h:1052
TInterface::BlueBgndMenuItem
TMenuItem * BlueBgndMenuItem
Definition: InterfaceUnit.h:427
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1645
TInterface::TTLabel1
TLabel * TTLabel1
Definition: InterfaceUnit.h:339
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:9349
TInterface::ResetChangedFileDataAndCaption
void ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
Called whenever the railway is changed to deal with title displays (loaded railway and timetable) and...
Definition: InterfaceUnit.cpp:16063
TTrain::MaxBrakeRate
double MaxBrakeRate
the maximum brake rate that the train can achieve
Definition: TrainUnit.h:389
TInterface::SpeedButton52
TSpeedButton * SpeedButton52
Definition: InterfaceUnit.h:556
TInterface::IMAGE_DIR_NAME
static const UnicodeString IMAGE_DIR_NAME
Definition: InterfaceUnit.h:870
TInterface::ShowPerformancePanel
bool ShowPerformancePanel
true when the 'show performance panel' button has been clicked during operation
Definition: InterfaceUnit.h:985
TInterface::LoadSessionDialog
TOpenDialog * LoadSessionDialog
Definition: InterfaceUnit.h:489
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TInterface::OutputLog10MouseDown
void __fastcall OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11260
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:523
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2436
TInterface::SpeedButton116
TSpeedButton * SpeedButton116
Definition: InterfaceUnit.h:620
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5222
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:149
TTrain::MidExitPos
int MidExitPos
Definition: TrainUnit.h:327
TInterface::NewSelectBitmapVLoc
int NewSelectBitmapVLoc
as above for VLoc
Definition: InterfaceUnit.h:1064
TInterface::MoveTextOrGraphic
@ MoveTextOrGraphic
Definition: InterfaceUnit.h:885
TInterface::ScreenGridButton
TBitBtn * ScreenGridButton
Definition: InterfaceUnit.h:72
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:7343
TInterface::EditMenu
TMenuItem * EditMenu
Definition: InterfaceUnit.h:429
TTrain::TrainFailed
bool TrainFailed
added at v2.4.0 to indicate failure
Definition: TrainUnit.h:371
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:384
DisplayUnit.h
TInterface::ResetSelectRect
void ResetSelectRect()
SelectRect is the rectangle selected via the 'Edit'menu, and this function sets left,...
Definition: InterfaceUnit.cpp:18623
TInterface::TTClockAdjustWarningHide
bool TTClockAdjustWarningHide
true if user opts not to show the timetable clock adjustment warning (false on starting the program)
Definition: InterfaceUnit.h:993
TInterface::TTLabel9
TLabel * TTLabel9
Definition: InterfaceUnit.h:347
TTrain::ZeroPowerNoFrontSplitMessage
bool ZeroPowerNoFrontSplitMessage
Definition: TrainUnit.h:300
TTrainController::SPADWarning
bool SPADWarning
Definition: TrainUnit.h:729
TInterface::TTClockAdjustCheckBox
TCheckBox * TTClockAdjustCheckBox
Definition: InterfaceUnit.h:229
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:11629
TInterface::TrackNotLinkedImage
TImage * TrackNotLinkedImage
Definition: InterfaceUnit.h:275
TTrain::DepartureTimeSet
bool DepartureTimeSet
set when stopped at a location and the next action is departure (set in UpdateTrain when ReleaseTime ...
Definition: TrainUnit.h:347
TInterface::WarningHover
bool WarningHover
true when mouse hovers over warning messages during operation - to prevent clicking while changing
Definition: InterfaceUnit.h:1009
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:6846
TInterface::SaveTTAsButton
TButton * SaveTTAsButton
Definition: InterfaceUnit.h:146
TInterface::ZoomButtonClick
void __fastcall ZoomButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8713
TInterface::SpeedButton90
TSpeedButton * SpeedButton90
Definition: InterfaceUnit.h:594
TTrain::LagElement
int LagElement
Definition: TrainUnit.h:327
TTrack::GetLocationName
AnsiString GetLocationName(unsigned int InactiveTrackVectorPosition)
Return location name for a given inactive track vector position.
Definition: TrackUnit.h:720
TTrainController::BufferAttentionWarning
bool BufferAttentionWarning
Definition: TrainUnit.h:729
TInterface::ExitTrackButtonClick
void __fastcall ExitTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1706
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:8662
TInterface::SpeedButton135
TSpeedButton * SpeedButton135
Definition: InterfaceUnit.h:639
TInterface::SpeedButton111
TSpeedButton * SpeedButton111
Definition: InterfaceUnit.h:615
TInterface::RouteCancelFlag
bool RouteCancelFlag
true when route cancel button pressed, enables a right mouse click to cancel a route if in an appropr...
Definition: InterfaceUnit.h:971
TTextHandler::LoadText
void LoadText(int Caller, std::ifstream &VecFile)
load the railway's text from VecFile
Definition: TextUnit.cpp:281
TInterface::SpeedToggleButton2Click
void __fastcall SpeedToggleButton2Click(TObject *Sender)
Definition: InterfaceUnit.cpp:11413
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:12722
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:14040
TInterface::LoadNormalSignalGlyphs
void LoadNormalSignalGlyphs(int Caller)
In trackbuild display normal signal types on signal buttons.
Definition: InterfaceUnit.cpp:18757
TInterface::MainScreenMouseDown3
void MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-out mode.
Definition: InterfaceUnit.cpp:7137
TInterface::TTLabel11
TLabel * TTLabel11
Definition: InterfaceUnit.h:348
TInterface::CancelTTEntryButton
TButton * CancelTTEntryButton
Definition: InterfaceUnit.h:137
TInterface::SpeedButton8
TSpeedButton * SpeedButton8
Definition: InterfaceUnit.h:512
TInterface::UserGraphicVectorNumber
int UserGraphicVectorNumber
used to store a single item of user graphics
Definition: InterfaceUnit.h:1106
TInterface::PreviousTTEntryButton
TButton * PreviousTTEntryButton
Definition: InterfaceUnit.h:128
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:16124
TInterface::TrackElementPanel
TPanel * TrackElementPanel
panel containing the track/location/parapet element buttons
Definition: InterfaceUnit.h:376
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:16959
TInterface::SelectionValid
bool SelectionValid
true when an area of screen has been selected via the 'Edit' & 'Select' or 'Reselect' menu items
Definition: InterfaceUnit.h:977
TDisplay::InvertElement
void InvertElement(int Caller, int HPos, int VPos)
Definition: DisplayUnit.cpp:140
TInterface::OperateButtonClick
void __fastcall OperateButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2033
TInterface::WhiteBgndMenuItem
TMenuItem * WhiteBgndMenuItem
Definition: InterfaceUnit.h:425
TInterface::ContinuationAutoSignals
void ContinuationAutoSignals(int Caller, TDateTime Now)
Deal with signal resetting on auto signal routes that extend to continuations where trains have depar...
Definition: InterfaceUnit.cpp:14409
TTrainController::CrashWarning
bool CrashWarning
Definition: TrainUnit.h:729
TInterface::LoadInterface
void LoadInterface(int Caller, std::ifstream &SessionFile)
Load the interface part of a session file.
Definition: InterfaceUnit.cpp:16524
TInterface::SpeedButton2
TSpeedButton * SpeedButton2
Definition: InterfaceUnit.h:506
TTrain::PlotTrain
void PlotTrain(int Caller, TDisplay *Disp)
Plots the train on the display in normal (zoomed-in) mode.
Definition: TrainUnit.cpp:7617
TInterface::AutoSigsFlag
bool AutoSigsFlag
true when AutoSig route building selected during operation
Definition: InterfaceUnit.h:931
TInterface::SetRouteButtonsInfoCaptionAndRouteNotStarted
void SetRouteButtonsInfoCaptionAndRouteNotStarted(int Caller)
Enables or disables the route type buttons depending on the route mode, sets the information panel me...
Definition: InterfaceUnit.cpp:17894
TInterface::MoveForwardsMenuItem
TMenuItem * MoveForwardsMenuItem
Definition: InterfaceUnit.h:463
TInterface::YardEdit
TEdit * YardEdit
Definition: InterfaceUnit.h:100
TInterface::SigPrefConsecButtonClick
void __fastcall SigPrefConsecButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2094
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3251
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:3992
TInterface::Paused
@ Paused
Definition: InterfaceUnit.h:877
TTrainController::SaveSessionTrains
void SaveSessionTrains(int Caller, std::ofstream &SessionFile)
save trains to a session file
Definition: TrainUnit.cpp:14055
TInterface::SpeedButton41
TSpeedButton * SpeedButton41
Definition: InterfaceUnit.h:545
TInterface::TrackInfoMenuItem
TMenuItem * TrackInfoMenuItem
Definition: InterfaceUnit.h:444
TRailGraphics::SpeedBut73NormBlackGlyph
Graphics::TBitmap * SpeedBut73NormBlackGlyph
Definition: GraphicUnit.h:1050
TInterface::Operating
@ Operating
Definition: InterfaceUnit.h:877
TTextHandler
A single object that handles text management.
Definition: TextUnit.h:62
TInterface::EditTimetableMenuItemClick
void __fastcall EditTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3205
TInterface::TakeSignallerControlMenuItemClick
void __fastcall TakeSignallerControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9838
TInterface::TimetableMode
@ TimetableMode
Definition: InterfaceUnit.h:855
TInterface::ScreenUpButtonClick
void __fastcall ScreenUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8654
TInterface::ShowHideTTButtonClick
void __fastcall ShowHideTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3382
TInterface::ImageMenu
TMenuItem * ImageMenu
Definition: InterfaceUnit.h:450
TInterface::LoadGroundSignalGlyphs
void LoadGroundSignalGlyphs(int Caller)
In trackbuild display ground signal types on signal buttons.
Definition: InterfaceUnit.cpp:18773
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:164
TInterface::CPArrivalsCheckBox
TCheckBox * CPArrivalsCheckBox
Definition: InterfaceUnit.h:242
TInterface::OneEntryTimetableMemo
TMemo * OneEntryTimetableMemo
the single service editing and display area on the right hand side of the timetable edit screen
Definition: InterfaceUnit.h:397
TInterface::SelectBitmapVLoc
int SelectBitmapVLoc
the original (prior to moving & after finished moving) VLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1084
TInterface::LengthOKButtonClick
void __fastcall LengthOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1361
TInterface::SpeedButton47
TSpeedButton * SpeedButton47
Definition: InterfaceUnit.h:551
TInterface::OutputLog1MouseDown
void __fastcall OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11172
NotStarted
@ NotStarted
Definition: TrainUnit.h:80
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4151
TInterface::AppDeactivate
void __fastcall AppDeactivate(TObject *Sender)
Definition: InterfaceUnit.cpp:759
TInterface::UnrestrictedButtonClick
void __fastcall UnrestrictedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2165
TInterface::ExportTTMenuItem
TMenuItem * ExportTTMenuItem
Definition: InterfaceUnit.h:415
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:5752
TInterface::SaveTTKeyFlag
bool SaveTTKeyFlag
Definition: InterfaceUnit.h:1030
TRailGraphics::SpeedBut71NormBlackGlyph
Graphics::TBitmap * SpeedBut71NormBlackGlyph
Definition: GraphicUnit.h:1048
TInterface::SelectNewGraphicClick
void __fastcall SelectNewGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12431
TInterface::SpeedButtonClick
void __fastcall SpeedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:884
TTrack::GetHLocMax
int GetHLocMax()
Definition: TrackUnit.h:770
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3127
TInterface::CPEditArrRange
TEdit * CPEditArrRange
Definition: InterfaceUnit.h:245
TInterface::ErrorButtonClick
void __fastcall ErrorButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10568
TTrainController::SPADEvents
int SPADEvents
Definition: TrainUnit.h:776
TInterface::PasteTTEntryButton
TButton * PasteTTEntryButton
Definition: InterfaceUnit.h:132
TInterface::SpeedButton139
TSpeedButton * SpeedButton139
Definition: InterfaceUnit.h:643
TInterface::SpeedButton3
TSpeedButton * SpeedButton3
Definition: InterfaceUnit.h:507
TTrain::ZeroPowerNoRepeatShuttleMessage
bool ZeroPowerNoRepeatShuttleMessage
Definition: TrainUnit.h:307
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TInterface::SetLevel2PrefDirMode
void SetLevel2PrefDirMode(int Caller)
Sets the Level2PrefDirMode user mode, using the Level2PrefDirMode variable to determine the mode.
Definition: InterfaceUnit.cpp:14138
TInterface::SetGapsButton
TBitBtn * SetGapsButton
Definition: InterfaceUnit.h:64
TTrain::ActionVectorEntryPtr
TActionVectorEntry * ActionVectorEntryPtr
points to the current position in the ActionVector (a member of the TTrainDataEntry class)
Definition: TrainUnit.h:335
TTrainDataEntry
Contains all data for a single train.
Definition: TrainUnit.h:177
clSignalStopBackground
#define clSignalStopBackground
Definition: GraphicUnit.h:299
TTrainController::LateDeps
int LateDeps
Definition: TrainUnit.h:769
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:17411
TInterface::ExitMenuItemClick
void __fastcall ExitMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5475
TrackUnit.h
TInterface::SpeedButton29
TSpeedButton * SpeedButton29
Definition: InterfaceUnit.h:533
TInterface::SpeedButton35
TSpeedButton * SpeedButton35
Definition: InterfaceUnit.h:539
TInterface::ScreenDownButtonClick
void __fastcall ScreenDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8594
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:17602
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:8691
TDisplay::ClearDisplay
void ClearDisplay(int Caller)
Empty the display.
Definition: DisplayUnit.cpp:181
TDisplay::Top
int Top()
Return the top pixel position of the screen.
Definition: DisplayUnit.h:120
TInterface::ExitPrefDirButtonClick
void __fastcall ExitPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1995
TInterface::SaveErrorFile
void SaveErrorFile()
Save the error log after an error has been thrown - no need for a caller.
Definition: InterfaceUnit.cpp:18014
TTrain::SendMissedActionLogs
void SendMissedActionLogs(int Caller, int IncNum, TActionVectorEntry *Ptr)
Missed actions (see NameInTimetableBeforeCDT above) sent to the performance log and performance file.
Definition: TrainUnit.cpp:5857
TInterface::SpeedVariableLabel2
TLabel * SpeedVariableLabel2
Definition: InterfaceUnit.h:113
TInterface::TrainInfoMenuItem
TMenuItem * TrainInfoMenuItem
Definition: InterfaceUnit.h:446
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1409
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1495
TInterface::TrainStatusInfoOnOffMenuItemClick
void __fastcall TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5539
TInterface::ConverttoRightHandSignalsMenuItem
TMenuItem * ConverttoRightHandSignalsMenuItem
Definition: InterfaceUnit.h:468
TInterface::SpeedButton96
TSpeedButton * SpeedButton96
Definition: InterfaceUnit.h:600
TInterface::TTClockxHalfButtonClick
void __fastcall TTClockxHalfButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11907
TInterface::OutputLog3
TLabel * OutputLog3
Definition: InterfaceUnit.h:294
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
TOnePrefDir::ExternalStorePrefDirElement
void ExternalStorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map - used by other classes.
Definition: TrackUnit.h:1324
clB5G5R4
#define clB5G5R4
Definition: GraphicUnit.h:285
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:665
TInterface::SaveImageNoGridMenuItemClick
void __fastcall SaveImageNoGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2552
TInterface::SpeedButton25
TSpeedButton * SpeedButton25
Definition: InterfaceUnit.h:529
TInterface::HelpMenu
TMenuItem * HelpMenu
Definition: InterfaceUnit.h:456
TInterface::TrackOKButtonClick
void __fastcall TrackOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:961
TTrainController::CheckSessionLockedRoutes
bool CheckSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for locked routes, true for success.
Definition: TrainUnit.cpp:14159
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:2855
TInterface::GapsSetImage
TImage * GapsSetImage
Definition: InterfaceUnit.h:276
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:14237
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TInterface::LocationNameComboBoxKeyUp
void __fastcall LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4704
TTrainController::CreateTTAnalysisFile
bool CreateTTAnalysisFile(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir, bool ArrChecked, bool DepChecked, bool AtLocChecked, int ArrRange, int DepRange)
Generate a timetable analysis file in the 'Formatted Timetables' folder, return false if failed for a...
Definition: TrainUnit.cpp:15002
TInterface::RevertToOriginalRouteSelector
void RevertToOriginalRouteSelector(int Caller)
Clears any route start markers, enables or disables the route cancel button, and resets the informati...
Definition: InterfaceUnit.cpp:13039
TInterface::FileIntegrityCheck
bool FileIntegrityCheck(int Caller, char *FileName) const
Check integrity of a railway file prior to loading, return true for success.
Definition: InterfaceUnit.cpp:12886
TInterface::TTLastServicePtr
TTEVPtr TTLastServicePtr
timetable entry value pointers used during timetable editing
Definition: InterfaceUnit.h:1147
TTrainController::CheckSessionTrains
bool CheckSessionTrains(int Caller, std::ifstream &InFile)
Part of the session file integrity check for train entries, true for success.
Definition: TrainUnit.cpp:14097
TInterface::SpeedButton126
TSpeedButton * SpeedButton126
Definition: InterfaceUnit.h:630
TakeSignallerControl
@ TakeSignallerControl
Definition: TrainUnit.h:49
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:11695
Simple
@ Simple
Definition: TrackUnit.h:63
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:693
TTrain::ZeroPowerNoRepeatShuttleOrNewServiceMessage
bool ZeroPowerNoRepeatShuttleOrNewServiceMessage
flags to indicate whether the respective message has been sent
Definition: TrainUnit.h:308
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TInterface::SetInitialTrackModeEditMenu
void SetInitialTrackModeEditMenu()
Enables or disables the initial Edit mode submenu items in Track mode.
Definition: InterfaceUnit.cpp:18546
TInterface::DeleteMenuItem
TMenuItem * DeleteMenuItem
Definition: InterfaceUnit.h:438
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2483
TInterface::TTClockAdjustOKButtonClick
void __fastcall TTClockAdjustOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12448
TInterface::ChangeDirectionMenuItemClick
void __fastcall ChangeDirectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10030
TInterface::PointsFlashDuration
float PointsFlashDuration
duration of the flash period when changing points manually
Definition: InterfaceUnit.h:1041
TInterface::LocationNameComboBoxClick
void __fastcall LocationNameComboBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4633
TInterface::TTServiceSyntaxCheckKeyFlag
bool TTServiceSyntaxCheckKeyFlag
Definition: InterfaceUnit.h:1028
TInterface::TLevel2OperMode
TLevel2OperMode
Definition: InterfaceUnit.h:876
TInterface::ConsecSignalsRoute
bool ConsecSignalsRoute
true when AutoSig or preferred route building selected during operation (always same state as Preferr...
Definition: InterfaceUnit.h:933
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:11923
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5182
TTrain::BackgroundColour
TColor BackgroundColour
the background colour of the train's headcode graphics
Definition: TrainUnit.h:455
TInterface::LengthCancelButtonClick
void __fastcall LengthCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1543
TTrain
Definition: TrainUnit.h:271
TInterface::OutputLog5
TLabel * OutputLog5
Definition: InterfaceUnit.h:296
TTrainController::CheckTimeValidity
bool CheckTimeValidity(int Caller, AnsiString TimeStr, TDateTime &Time)
returns true if the time complies with requirements
Definition: TrainUnit.cpp:9798
clSignallerStopped
#define clSignallerStopped
Definition: GraphicUnit.h:298
TTextHandler::SelectTextVector
TTextVector SelectTextVector
Definition: TextUnit.h:69
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:151
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:10391
TInterface::CallOnImage
TImage * CallOnImage
Definition: InterfaceUnit.h:262
TInterface::PerformancePanelDragStartY
int PerformancePanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1075
TInterface::LocationNameTextBox
TEdit * LocationNameTextBox
edit box that accepts location names
Definition: InterfaceUnit.h:94
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:542
TInterface::SaveSessionFlag
bool SaveSessionFlag
true when a session save command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:973
TTrainController::ContinuationTrainExpectationMultiMap
TContinuationTrainExpectationMultiMap ContinuationTrainExpectationMultiMap
Multimap for TContinuationTrainExpectationEntry objects, the access key is the expectation time.
Definition: TrainUnit.h:799
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:6861
TInterface::SpeedButton73
TSpeedButton * SpeedButton73
Definition: InterfaceUnit.h:577
TInterface::TTLabel4
TLabel * TTLabel4
Definition: InterfaceUnit.h:342
TTrain::StoppedForTrainInFront
bool StoppedForTrainInFront
Definition: TrainUnit.h:432
TInterface::ConflictAnalysisKeyFlag
bool ConflictAnalysisKeyFlag
Definition: InterfaceUnit.h:1034
GapJump
@ GapJump
Definition: TrackUnit.h:63
TInterface::Level2OperMode
enum TInterface::TLevel2OperMode Level2OperMode
TInterface::SigsOnRightImage1
TImage * SigsOnRightImage1
Definition: InterfaceUnit.h:282
TInterface::SaveRailwayPDPButton
TBitBtn * SaveRailwayPDPButton
Save button on PrefDirPanel.
Definition: InterfaceUnit.h:119
TInterface::SpeedButton62
TSpeedButton * SpeedButton62
Definition: InterfaceUnit.h:566
TInterface::SpeedButton58
TSpeedButton * SpeedButton58
Definition: InterfaceUnit.h:562
TTrainController::MissedStops
int MissedStops
Definition: TrainUnit.h:771
TInterface::TempTTFileName
AnsiString TempTTFileName
the name for the temporary file used to save loaded timetables for storage in session files & error l...
Definition: InterfaceUnit.h:922
TInterface::PrefDirMode
@ PrefDirMode
Definition: InterfaceUnit.h:855
TInterface::PassRedSignalMenuItem
TMenuItem * PassRedSignalMenuItem
Definition: InterfaceUnit.h:464
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:147
TRailGraphics::bmGreenRect
Graphics::TBitmap * bmGreenRect
Definition: GraphicUnit.h:521
TInterface::TTClockExitButtonClick
void __fastcall TTClockExitButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11770
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:147
TTrack::IsReadyForOperation
bool IsReadyForOperation(bool GiveMessage)
Indicates whether or not the railway is ready for saving as a '.rly' file and for operation.
Definition: TrackUnit.h:726
TTrack::Raising
@ Raising
Definition: TrackUnit.h:523
TInterface::OAListBoxRightMouseButtonDown
bool OAListBoxRightMouseButtonDown
flag set when right mouse button clicked over op action list box, so floating information window show...
Definition: InterfaceUnit.h:959
TTrainController::FinishedOperation
void FinishedOperation(int Caller)
called when exiting operation mode to delete all trains and timetable data etc
Definition: TrainUnit.cpp:8263
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:557
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:9418
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TTrain::MidElement
int MidElement
Definition: TrainUnit.h:327
TInterface::SpeedButton5
TSpeedButton * SpeedButton5
Definition: InterfaceUnit.h:509
TInterface::LocationNameKeyUp
void __fastcall LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:1153
TInterface::LoadUserGraphicDialog
TOpenDialog * LoadUserGraphicDialog
Definition: InterfaceUnit.h:491
TAllRoutes::CallonVector
std::vector< TCallonEntry > CallonVector
the store of all call-on entries
Definition: TrackUnit.h:1554
TInterface::OutputLog8MouseDown
void __fastcall OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11240
TTrain::LeadElement
int LeadElement
Definition: TrainUnit.h:327
TInterface::SetPausedOrZoomedInfoCaption
void SetPausedOrZoomedInfoCaption(int Caller)
Sets the information panel message for zoom-out or paused modes.
Definition: InterfaceUnit.cpp:17982
TInterface::CurDir
AnsiString CurDir
the full path to the folder where railway.exe resides
Definition: InterfaceUnit.h:908
TInterface::OneEntryTimetableMemoKeyUp
void __fastcall OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4661
TInterface::RouteCancelButton
TBitBtn * RouteCancelButton
Definition: InterfaceUnit.h:198
TInterface::SpeedButton26
TSpeedButton * SpeedButton26
Definition: InterfaceUnit.h:530
TInterface::HomeButton
TBitBtn * HomeButton
Definition: InterfaceUnit.h:253
TRailGraphics
Handles graphic data & functions, single object defined.
Definition: GraphicUnit.h:308
TInterface::OperatorActionPanelDragStartY
int OperatorActionPanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1068
TTrain::RepeatNumber
int RepeatNumber
indicates which of the repeating services this train represents (0 = first service)
Definition: TrainUnit.h:321
TTrainDataEntry::ActionVector
TActionVector ActionVector
all the actions for the train
Definition: TrainUnit.h:195
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:638
TInterface::NewHomeButton
TBitBtn * NewHomeButton
Definition: InterfaceUnit.h:254
TInterface::ResetAll
void ResetAll(int Caller)
Called during ClearEverything and on startup to reset all major railway data values.
Definition: InterfaceUnit.cpp:15877
TInterface::SpeedButton75
TSpeedButton * SpeedButton75
Definition: InterfaceUnit.h:579
TTrainController::LoadSessionLockedRoutes
void LoadSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
load locked routes from a session file
Definition: TrainUnit.cpp:14138
TInterface::DistancesMarked
bool DistancesMarked
true when setting lengths, used to ensure the screen distance markers are redisplayed when the screen...
Definition: InterfaceUnit.h:941
TTrainController::EarlyPasses
int EarlyPasses
Definition: TrainUnit.h:766
TTrain::HeadCode
AnsiString HeadCode
needs own HeadCode because repeat entries will differ from TrainDataEntry.HeadCode
Definition: TrainUnit.h:290
TInterface::TrackBuildPanel
TPanel * TrackBuildPanel
'Build/modify railway' panel
Definition: InterfaceUnit.h:357
TTrain::EntryTime
TDateTime EntryTime
Definition: TrainUnit.h:414
TInterface::CutMoving
@ CutMoving
Definition: InterfaceUnit.h:886
TInterface::SpeedButton134
TSpeedButton * SpeedButton134
Definition: InterfaceUnit.h:638
TInterface::SelectLengthsMenuItem
TMenuItem * SelectLengthsMenuItem
Definition: InterfaceUnit.h:439
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1275
TInterface::SpeedButton72
TSpeedButton * SpeedButton72
Definition: InterfaceUnit.h:576
TInterface::ValidateTimetableButton
TButton * ValidateTimetableButton
Definition: InterfaceUnit.h:144
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5413
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1415
InterfaceUnit.h
TInterface::CopyMenuItemClick
void __fastcall CopyMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9033
TInterface::PerformanceLogButton
TBitBtn * PerformanceLogButton
Definition: InterfaceUnit.h:200
TInterface::FORMATTEDTT_DIR_NAME
static const UnicodeString FORMATTEDTT_DIR_NAME
Definition: InterfaceUnit.h:871
TInterface::HighLightOneGap
bool HighLightOneGap(int Caller, int &HLoc, int &VLoc)
Called during gap setting to mark a gap with a red ellipse and ask user to select the corresponding g...
Definition: InterfaceUnit.cpp:12808
TTrain::OneLengthAccelDecel
bool OneLengthAccelDecel
set when a train can only move forwards one element before stopping but needs to accelerate for the f...
Definition: TrainUnit.h:357
TTrain::FloatingLabelNextString
AnsiString FloatingLabelNextString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the 'Next' action.
Definition: TrainUnit.cpp:6417
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:534
TTrain::FailedTrainNoFinishJoinMessage
bool FailedTrainNoFinishJoinMessage
Definition: TrainUnit.h:302
TInterface::SpeedButton55
TSpeedButton * SpeedButton55
Definition: InterfaceUnit.h:559
TInterface::OperatorActionPanel
TPanel * OperatorActionPanel
new v2.2.0 panel housing the OAListBox with list of trains and times to act
Definition: InterfaceUnit.h:385
TInterface::NextTTEntryButton
TButton * NextTTEntryButton
Definition: InterfaceUnit.h:129
TTextHandler::SelectTextVectorSize
unsigned int SelectTextVectorSize(int Caller)
return the number of items in SelectTextVector
Definition: TextUnit.cpp:516
TInterface::TrackTrainFloat
void TrackTrainFloat(int Caller)
Controls the floating window function, called during the ClockTimer2 function.
Definition: InterfaceUnit.cpp:14466
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:138
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TInterface::AddLocationNameText
void AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
Add 'Name' to TextVector and display on screen at a position determined by the shape and size of the ...
Definition: InterfaceUnit.cpp:18652
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackElement.at(At)
Definition: TrackUnit.cpp:9524
TTextHandler::CheckTextElementsInFile
bool CheckTextElementsInFile(int Caller, std::ifstream &VecFile)
check the validity of text items in VecFile prior to loading, return true for success
Definition: TextUnit.cpp:349
TInterface::ConverttoRightHandSignalsMenuItemClick
void __fastcall ConverttoRightHandSignalsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12216
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:295
TTrack::GetVLocMax
int GetVLocMax()
Definition: TrackUnit.h:780
TTrainController::LoadSessionContinuationAutoSigEntries
void LoadSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
load ContinuationAutoSigEntries from a session file
Definition: TrainUnit.cpp:14221
TInterface::HighlightOneEntryInAllEntriesTTListBox
void HighlightOneEntryInAllEntriesTTListBox(int Caller, int Position)
Called during timetable editing to highlight in red a single entry in the list of all entries in the ...
Definition: InterfaceUnit.cpp:5409
TInterface::DistanceStart
@ DistanceStart
Definition: InterfaceUnit.h:885
TInterface::ErrorMessage
TMemo * ErrorMessage
the text of the normal error message screen
Definition: InterfaceUnit.h:393
TInterface::ExitPrefDirButton
TBitBtn * ExitPrefDirButton
Definition: InterfaceUnit.h:121
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:701
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:123
TInterface::TrackLengthPanel
TPanel * TrackLengthPanel
the panel that contains the distance/speed setting buttons and edit boxes
Definition: InterfaceUnit.h:378
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:520
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3410
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:989
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:990
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:757
TTrainController::OtherMissedEvents
int OtherMissedEvents
Definition: TrainUnit.h:775
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:425
TInterface::MoveTextOrGraphicButton
TBitBtn * MoveTextOrGraphicButton
Definition: InterfaceUnit.h:67
TTrainDataEntry::Description
AnsiString Description
headcode is the first train's headcode, rest are calculated from repeat information; ServiceReference...
Definition: TrainUnit.h:179
TInterface::RouteContinuing
@ RouteContinuing
Definition: InterfaceUnit.h:890
TTrain::ExitSpeedHalf
double ExitSpeedHalf
speed when half way into the next element
Definition: TrainUnit.h:379
SignalPost
@ SignalPost
Definition: TrackUnit.h:63
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:8656
TTrain::LastActionTime
TDateTime LastActionTime
time of the last timetabled action, used to ensure at least a 30 second delay before the next action
Definition: TrainUnit.h:418
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:16112
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:421
TInterface::InfoPanel
TPanel * InfoPanel
the general information panel (with blue 'i' symbol)
Definition: InterfaceUnit.h:372
TInterface::TextOrUserGraphicGridButtonClick
void __fastcall TextOrUserGraphicGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1761
TInterface::FormKeyDown
void __fastcall FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:10671
TInterface::MoveTTEntryDownButton
TButton * MoveTTEntryDownButton
Definition: InterfaceUnit.h:135
TInterface::CheckTimetableFromSessionFile
bool CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Check the timetable file embedded within a session file & return false for error, called during Sessi...
Definition: InterfaceUnit.cpp:17078
TRailGraphics::SpeedBut71GrndBlackGlyph
Graphics::TBitmap * SpeedBut71GrndBlackGlyph
Definition: GraphicUnit.h:1056
TInterface::DeleteTTEntryButtonClick
void __fastcall DeleteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3837
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:6875
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6157
TInterface::WarningFlashCount
int WarningFlashCount
increments each clock cycle to a max. of 4 then resets to 0, used to toggle bool WarningFlash - see a...
Definition: InterfaceUnit.h:1110
TInterface::StartWholeRailwayMoveHPos
int StartWholeRailwayMoveHPos
mouse X position when start to move the whole railway
Definition: InterfaceUnit.h:1088
TInterface::SpeedButton93
TSpeedButton * SpeedButton93
Definition: InterfaceUnit.h:597
TInterface::SpeedButton119
TSpeedButton * SpeedButton119
Definition: InterfaceUnit.h:623
TInterface::SelectedGraphicFileName
AnsiString SelectedGraphicFileName
filename for selected graphic set during LoadGraphic
Definition: InterfaceUnit.h:926
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:7996
TInterface::TrackBuildPanelLabel
TLabel * TrackBuildPanelLabel
label to the left of TrackBuildPanel
Definition: InterfaceUnit.h:315
clNormalBackground
#define clNormalBackground
Definition: GraphicUnit.h:297
TInterface::TTClockAdjButtonClick
void __fastcall TTClockAdjButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11739
TInterface::RAILWAY_DIR_NAME
static const UnicodeString RAILWAY_DIR_NAME
Definition: InterfaceUnit.h:866
TTrainController::SecondPassActions
bool SecondPassActions(int Caller, bool GiveMessages)
Carry out further detailed timetable consistency checks, return true for success.
Definition: TrainUnit.cpp:10838
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:16097
TInterface::SPADImage
TImage * SPADImage
Definition: InterfaceUnit.h:266
TInterface::AddTrackButton
TBitBtn * AddTrackButton
Definition: InterfaceUnit.h:63
TInterface::MainMenu1
TMainMenu * MainMenu1
the program menu
Definition: InterfaceUnit.h:390
TInterface::OutputLog7MouseDown
void __fastcall OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11230
Concourse
@ Concourse
Definition: TrackUnit.h:64
TTextHandler::TTextVectorIterator
std::vector< TTextItem >::iterator TTextVectorIterator
Definition: TextUnit.h:66
TTrainController::SPADRisks
int SPADRisks
Definition: TrainUnit.h:777
TInterface::LocationNamesNotSetImage
TImage * LocationNamesNotSetImage
Definition: InterfaceUnit.h:279
TInterface::FloatingPanel
TPanel * FloatingPanel
new for v2.2.0 where label sits in it and it autosizes to the label. Labels are not TWinControls so t...
Definition: InterfaceUnit.h:382
TRailGraphics::SpeedBut68NormBlackGlyph
Graphics::TBitmap * SpeedBut68NormBlackGlyph
Definition: GraphicUnit.h:1045
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:710
TInterface::SaveMenuItemClick
void __fastcall SaveMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2484
TInterface::ScreenGridButtonClick
void __fastcall ScreenGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1865
TTrain::EntrySpeed
double EntrySpeed
speed at which the train enters the next element
Definition: TrainUnit.h:377
TInterface::UserGraphicMoveHPos
int UserGraphicMoveHPos
Definition: InterfaceUnit.h:1108
TInterface::PassRedSignalMenuItemClick
void __fastcall PassRedSignalMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10302
TInterface::ReselectMenuItem
TMenuItem * ReselectMenuItem
Definition: InterfaceUnit.h:431
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:12379
TInterface::ClearEverything
bool ClearEverything(int Caller)
First check whether a railway file has changed and if so ask user if really wants to close it without...
Definition: InterfaceUnit.cpp:12836
TInterface::PrefDirContinuing
@ PrefDirContinuing
Definition: InterfaceUnit.h:881
TTrain::TrainGone
bool TrainGone
set when train has left the railway, so it can be removed from the display at the next clock tick
Definition: TrainUnit.h:428
TRailGraphics::SpeedBut70NormBlackGlyph
Graphics::TBitmap * SpeedBut70NormBlackGlyph
Definition: GraphicUnit.h:1047
TTrainController::OnTimePasses
int OnTimePasses
Definition: TrainUnit.h:774
TInterface::SaveAsMenuItem
TMenuItem * SaveAsMenuItem
Definition: InterfaceUnit.h:411
TInterface::MoveTextOrGraphicButtonClick
void __fastcall MoveTextOrGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1075
TTrainController::SigSHigh
bool SigSHigh
Definition: TrainUnit.h:743
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4076
TInterface::ZoomButton
TBitBtn * ZoomButton
Definition: InterfaceUnit.h:255
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1597
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:94
TInterface::CopyTTEntryButton
TButton * CopyTTEntryButton
Definition: InterfaceUnit.h:130
TInterface::ErrorMessageStoreImage
TMemo * ErrorMessageStoreImage
the text of the error message for failure to draw trains in SaveOperatingImage
Definition: InterfaceUnit.h:395
TInterface::SpeedButton76
TSpeedButton * SpeedButton76
Definition: InterfaceUnit.h:580
TTrain::StoppedAfterSPAD
bool StoppedAfterSPAD
Definition: TrainUnit.h:432
TInterface::SpeedButton145
TSpeedButton * SpeedButton145
Definition: InterfaceUnit.h:649
TInterface::NoPrefDirMode
@ NoPrefDirMode
Definition: InterfaceUnit.h:881
TInterface::SpeedButton88
TSpeedButton * SpeedButton88
Definition: InterfaceUnit.h:592
TTrainController::OnTimeArrivals
int OnTimeArrivals
Definition: TrainUnit.h:772
TInterface::MoveTTEntryDownButtonClick
void __fastcall MoveTTEntryDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4347
TInterface::PerformanceLogBox
TMemo * PerformanceLogBox
the performance log displayed during operation
Definition: InterfaceUnit.h:399
TRailGraphics::SpeedBut72GrndBlackGlyph
Graphics::TBitmap * SpeedBut72GrndBlackGlyph
Definition: GraphicUnit.h:1057
TInterface::SpeedButton28
TSpeedButton * SpeedButton28
Definition: InterfaceUnit.h:532
TAllRoutes::LevelCrossingBarrierUpDelay
const float LevelCrossingBarrierUpDelay
the full value in seconds for which the level crossing flashes prior to closing to trains
Definition: TrackUnit.h:1574
TInterface::SpeedTopLabel
TLabel * SpeedTopLabel
Definition: InterfaceUnit.h:180
TInterface::OperateButton
TBitBtn * OperateButton
Definition: InterfaceUnit.h:194
clFrontCodeSignaller
#define clFrontCodeSignaller
Definition: GraphicUnit.h:295
TInterface::SignallerJoinedByMenuItemClick
void __fastcall SignallerJoinedByMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10123
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:675
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TActionVectorEntry::ArrivalTime
TDateTime ArrivalTime
Definition: TrainUnit.h:106
TTrain::StoppedAtBuffers
bool StoppedAtBuffers
Definition: TrainUnit.h:432
TInterface::SkipFormResizeEvent
bool SkipFormResizeEvent
added at v2.1.0 to avoid calling the event during startup and shutdown
Definition: InterfaceUnit.h:987
TTrain::Mass
int Mass
in kg
Definition: TrainUnit.h:408
TInterface::TrackInfoOnOffMenuItem
TMenuItem * TrackInfoOnOffMenuItem
Definition: InterfaceUnit.h:445
TDisplay::ShowWarningLog
void ShowWarningLog(int Caller)
Show the warnings after timetable clock adjusted.
Definition: DisplayUnit.cpp:493
TInterface::SpeedButton121
TSpeedButton * SpeedButton121
Definition: InterfaceUnit.h:625
TTrainController::ProcessOneTimetableLine
bool ProcessOneTimetableLine(int Caller, int Count, AnsiString OneLine, bool &EndOfFile, bool FinalCall, bool GiveMessages, bool CheckLocationsExistInRailway)
Carry out preliminary (mainly syntax) validity checks on a single timetable service entry and (if Fin...
Definition: TrainUnit.cpp:9148
TInterface::SaveAsMenuItemClick
void __fastcall SaveAsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2535
TTextItem
A single piece of text that can be displayed on the railway.
Definition: TextUnit.h:36
TInterface::SpeedButton136
TSpeedButton * SpeedButton136
Definition: InterfaceUnit.h:640
TInterface::PointFlash
TGraphicElement * PointFlash
Definition: InterfaceUnit.h:1124
TInterface::TrackLinkedImage
TImage * TrackLinkedImage
Definition: InterfaceUnit.h:274
TTrain::LeadExitPos
int LeadExitPos
Definition: TrainUnit.h:327
TInterface::SelectPickedUp
bool SelectPickedUp
true when a valid selected screen area has been clicked after a 'Copy' or 'Cut' selected in the 'Edit...
Definition: InterfaceUnit.h:981
TDisplay::ResetZoomOutOffsets
void ResetZoomOutOffsets()
Reset the zoomed-out screen display to the 'Home' position.
Definition: DisplayUnit.h:208
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:156
TInterface::DevelopmentPanel
TPanel * DevelopmentPanel
used for diagnostic purposes, made visible by ctrl+ alt+ 3
Definition: InterfaceUnit.h:380
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1616
TInterface::PerformancePanel
TPanel * PerformancePanel
displays the operating performance log
Definition: InterfaceUnit.h:374
TTrainController::DerailWarning
bool DerailWarning
Definition: TrainUnit.h:729
TInterface::CopyMoving
@ CopyMoving
Definition: InterfaceUnit.h:886
TInterface::TimetableEditPanel
TPanel * TimetableEditPanel
the large panel that contains all the main timetable components
Definition: InterfaceUnit.h:366
TInterface::RouteMode
enum TInterface::@0 RouteMode
route building modes
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TInterface::TrainStatusInfoOnOffMenuItem
TMenuItem * TrainStatusInfoOnOffMenuItem
Definition: InterfaceUnit.h:447
TInterface::SetLengthsButtonClick
void __fastcall SetLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1340
TInterface::SaveTTEntryButton
TButton * SaveTTEntryButton
Definition: InterfaceUnit.h:136
TInterface::SpeedButton37
TSpeedButton * SpeedButton37
Definition: InterfaceUnit.h:541
TInterface::BaseMode
@ BaseMode
Definition: InterfaceUnit.h:855
TInterface::SpeedEditBoxKeyUp
void __fastcall SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11434
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:10204
TInterface::MirrorMenuItem
TMenuItem * MirrorMenuItem
Definition: InterfaceUnit.h:435
TInterface::EveryPrefDir
TOnePrefDir * EveryPrefDir
all the Pref Dir elements in the railway
Definition: InterfaceUnit.h:1135
TTrainController::TotLateDepMins
float TotLateDepMins
Definition: TrainUnit.h:759
TDisplay::ZoomOutFlag
bool ZoomOutFlag
true when zoomed-out
Definition: DisplayUnit.h:69
TInterface::OutputLog8
TLabel * OutputLog8
Definition: InterfaceUnit.h:299
TInterface::SpeedButton1
TSpeedButton * SpeedButton1
See Speedbutton1 detail for track element allocations.
Definition: InterfaceUnit.h:505
TTrainController::TrainVector
TTrainVector TrainVector
vector containing all trains currently in the railway
Definition: TrainUnit.h:807
TInterface::SaveAsSubroutine
void SaveAsSubroutine(int Caller)
Used to save a railway when not already saved - e.g. when not already named or when the 'Save as' men...
Definition: InterfaceUnit.cpp:18446
TInterface::MainScreenMouseDown2
void MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-in mode.
Definition: InterfaceUnit.cpp:5716
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1421
TInterface::RepairFailedTrainMenuItemClick
void __fastcall RepairFailedTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10212
TInterface::AddLocationName
@ AddLocationName
Definition: InterfaceUnit.h:885
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:7794
TTrack::IsTrackFinished
bool IsTrackFinished()
Indicates whether or not the track has been successfully linked together.
Definition: TrackUnit.h:732
TAllRoutes::AllRoutesClear
void AllRoutesClear()
Erases all routes from AllRoutesVector and from Route2MultiMap.
Definition: TrackUnit.h:1602
TRailGraphics::SpeedBut74GrndBlackGlyph
Graphics::TBitmap * SpeedBut74GrndBlackGlyph
Definition: GraphicUnit.h:1059
TAllRoutes::PointsDelay
const float PointsDelay
the value in seconds for which points flash prior to being changed. Used for the points flash period ...
Definition: TrackUnit.h:1578
TInterface::SaveSession
void SaveSession(int Caller)
Save a session file - see LoadSession for details of additions to the session file.
Definition: InterfaceUnit.cpp:16085
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TAllRoutes::SignalsDelay
const float SignalsDelay
the value in seconds for which signals flash prior to being changed. Used for the route flash period ...
Definition: TrackUnit.h:1580
TDisplay::GetFont
TFont * GetFont()
Return the current screen font.
Definition: DisplayUnit.h:132
TInterface::SpeedButton10
TSpeedButton * SpeedButton10
Definition: InterfaceUnit.h:514
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:284
TInterface::SpeedButton103
TSpeedButton * SpeedButton103
Definition: InterfaceUnit.h:607
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:757
TTrainController::TotEarlyArrMins
float TotEarlyArrMins
values for performance file summary
Definition: TrainUnit.h:755
TInterface::PerformancePanelStartDrag
void __fastcall PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5644
TInterface::TempCursorSet
bool TempCursorSet
indicates that a screen cursor has been stored in TempCursor for redisplay after a temporary cursor (...
Definition: InterfaceUnit.h:989
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:11182
TInterface::SpeedButton85
TSpeedButton * SpeedButton85
Definition: InterfaceUnit.h:589
TInterface::PasteMenuItemClick
void __fastcall PasteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9619
TInterface::MainScreenMouseUp
void __fastcall MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7441
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TInterface::SaveTempTimetableFile
void SaveTempTimetableFile(int Caller, AnsiString InFileName)
Save a timetable as a temporary file either on loading directly or on loading a session file....
Definition: InterfaceUnit.cpp:18207
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1584
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TInterface::RotateMenuItemClick
void __fastcall RotateMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9168
TTrainDataEntry::SignallerSpeed
int SignallerSpeed
in km/h for use when under signaller control
Definition: TrainUnit.h:191
TInterface::OverallDistance
int OverallDistance
Definition: InterfaceUnit.h:1070
TInterface::SpeedButton105
TSpeedButton * SpeedButton105
Definition: InterfaceUnit.h:609
TInterface::SpeedButton83
TSpeedButton * SpeedButton83
Definition: InterfaceUnit.h:587
TTrain::AbleToMove
bool AbleToMove(int Caller)
Indicates that a train is not prevented from moving - used to allow appropriate popup menu options wh...
Definition: TrainUnit.cpp:6282
TTrainController::MTBFHours
double MTBFHours
Mean time between failures in timetable clock hours.
Definition: TrainUnit.h:746
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:11662
TInterface::RestoreAllDefaultLengthsButtonClick
void __fastcall RestoreAllDefaultLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1671
TInterface::LengthWarningSentFlag
bool LengthWarningSentFlag
indicates that the length selection applying to all elements in the selection warning has been given,...
Definition: InterfaceUnit.h:951
TInterface::SpeedButton131
TSpeedButton * SpeedButton131
Definition: InterfaceUnit.h:635
TInterface::FlipMenuItemClick
void __fastcall FlipMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9052
TInterface::TrainTTInfoOnOffMenuItem
TMenuItem * TrainTTInfoOnOffMenuItem
Definition: InterfaceUnit.h:448
TInterface::AllSetUpFlag
bool AllSetUpFlag
false during initial start up, true when all set up to allow MasterClock to start
Definition: InterfaceUnit.h:929
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3228
TInterface::LocationNameButton
TBitBtn * LocationNameButton
Definition: InterfaceUnit.h:68
TInterface::SpeedButton101
TSpeedButton * SpeedButton101
Definition: InterfaceUnit.h:605
TTrain::TrainMode
TTrainMode TrainMode
mode of operation - either Timetable (running under timetable control) or Signaller (running under si...
Definition: TrainUnit.h:420
TInterface::LoadRailway
void LoadRailway(int Caller, AnsiString LoadFileName)
Load a railway file. The Active elements marker now has a '1' at the end if there are user graphics t...
Definition: InterfaceUnit.cpp:2354
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:10251
TInterface::TextOrUserGraphicGridButton
TBitBtn * TextOrUserGraphicGridButton
Definition: InterfaceUnit.h:70
TInterface::PointFlashVectorPosition
int PointFlashVectorPosition
Definition: InterfaceUnit.h:1077
TInterface::AddSubMinsBoxKeyUp
void __fastcall AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4686
TInterface::ExitOperationButtonClick
void __fastcall ExitOperationButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2256
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1499
TInterface::TTClockAdd1hButtonClick
void __fastcall TTClockAdd1hButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11982
TUtilities::Format96HHMM
AnsiString Format96HHMM(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm where hh runs from 00 to 95 & resets when it...
Definition: Utilities.cpp:535
TInterface::TTClockx2ButtonClick
void __fastcall TTClockx2ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11812
TInterface::PerformancePanelDragStartX
int PerformancePanelDragStartX
mouse 'X' position when the performance panel begins to be dragged
Definition: InterfaceUnit.h:1073
TInterface::SpeedButton45
TSpeedButton * SpeedButton45
Definition: InterfaceUnit.h:549
TInterface::SpeedEditBox2KeyUp
void __fastcall SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11588
TInterface::SavedFileName
AnsiString SavedFileName
the full path and filename of the loaded railway
Definition: InterfaceUnit.h:920
TInterface::FillSelectionMessageSentFlag
bool FillSelectionMessageSentFlag
indicates that the message about filling a selected area with a chosen track element has been given,...
Definition: InterfaceUnit.h:947
TInterface::PlanPrefDirsMenuItemClick
void __fastcall PlanPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1892
TInterface::OperatingPanel
TPanel * OperatingPanel
'Operate railway' panel
Definition: InterfaceUnit.h:363
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:818
TInterface::SpeedButton141
TSpeedButton * SpeedButton141
Definition: InterfaceUnit.h:645
TInterface::ShowOperatorActionPanel
bool ShowOperatorActionPanel
true when the 'trains needing action' button has been clicked during operation (new at v2....
Definition: InterfaceUnit.h:1003
TTrack::GetGapVLoc
int GetGapVLoc()
Definition: TrackUnit.h:765
TInterface::SpeedButton124
TSpeedButton * SpeedButton124
Definition: InterfaceUnit.h:628
TUtilities::CheckFileString
bool CheckFileString(std::ifstream &InFile)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success
Definition: Utilities.cpp:356
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:11482
TRailGraphics::bmGrid
Graphics::TBitmap * bmGrid
Definition: GraphicUnit.h:522
TInterface::RestoreFocusPanel
TPanel * RestoreFocusPanel
Panel used to restore focus to Interface to enable cursor keys to move screen.
Definition: InterfaceUnit.h:354
TInterface::BlackBgndMenuItem
TMenuItem * BlackBgndMenuItem
Definition: InterfaceUnit.h:426
SignallerControlStop
@ SignallerControlStop
Definition: TrainUnit.h:51
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:710
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:538
TInterface::FloatingLabel
TLabel * FloatingLabel
the floating window that displays track & train information
Definition: InterfaceUnit.h:335
TInterface::NewTTEntryButton
TButton * NewTTEntryButton
Definition: InterfaceUnit.h:138
TTrainController::ExcessLCDownMins
float ExcessLCDownMins
total excess time in minutes over the 3 minutes barriers down allowance for level crossings
Definition: TrainUnit.h:753
TInterface::SubMinsButtonClick
void __fastcall SubMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3589
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:346
TInterface::TimetableControlMenuItemClick
void __fastcall TimetableControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9911
TTrack::TActiveTrackElementNameIterator
TActiveTrackElementNameMap::iterator TActiveTrackElementNameIterator
Definition: TrackUnit.h:617
TInterface::DistanceBox
TEdit * DistanceBox
distance/speed setting edit box that accepts distances
Definition: InterfaceUnit.h:90
TInterface::SpeedButton142
TSpeedButton * SpeedButton142
Definition: InterfaceUnit.h:646
TInterface::PresetAutoSigRoutesButton
TBitBtn * PresetAutoSigRoutesButton
Definition: InterfaceUnit.h:199
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:133
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:117
TInterface::TTLabel12
TLabel * TTLabel12
Definition: InterfaceUnit.h:349
TInterface::TTServiceSyntaxCheckButtonClick
void __fastcall TTServiceSyntaxCheckButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4198
TInterface::SpeedButton57
TSpeedButton * SpeedButton57
Definition: InterfaceUnit.h:561
TInterface::TTClockSpeed
float TTClockSpeed
rate at which the timetable clock runs 1 = normal
Definition: InterfaceUnit.h:1045
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TDisplay::PlotAbsolute
void PlotAbsolute(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Definition: DisplayUnit.cpp:419
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5141
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1533
TInterface::TTClockx4ButtonClick
void __fastcall TTClockx4ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11831
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:12316
TTextHandler::TextFound
bool TextFound(int Caller, int HPosInput, int VPosInput, AnsiString &Text)
look for a text item in the vicinity of HPosInput & VPosInput, return true if found & return the foun...
Definition: TextUnit.cpp:225
TInterface::LCManualLowerBarriersMessageSent
bool LCManualLowerBarriersMessageSent
indicates that the manual LC operation message has been given, so it won't be given again
Definition: InterfaceUnit.h:949
TInterface::SaveImageAndPrefDirsMenuItemClick
void __fastcall SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2741
TInterface::AddMinsButton
TButton * AddMinsButton
Definition: InterfaceUnit.h:141
SignallerStepForward
@ SignallerStepForward
Definition: TrainUnit.h:51
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:775
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:527
TInterface::SpeedButton60
TSpeedButton * SpeedButton60
Definition: InterfaceUnit.h:564
TInterface::TrackInfoOnOffMenuItemClick
void __fastcall TrackInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5516
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3436
TTrainController::OpTimeToActUpdateCounter
unsigned int OpTimeToActUpdateCounter
new v2.2.0, incremented in Interface.cpp, controls updating for OpTimeToActPanel
Definition: TrainUnit.h:791
TTrain::BeingCalledOn
bool BeingCalledOn
in course of being called on to a station
Definition: TrainUnit.h:341
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:217
TInterface::AZOrderButtonClick
void __fastcall AZOrderButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5051
TInterface::HiddenScreen
TImage * HiddenScreen
a hidden copy of the railway display screen used during ClearandRebuildRailway (see below) to avoid f...
Definition: InterfaceUnit.h:1130
TInterface::PerformancePanelLabelStartDrag
void __fastcall PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:10579
TInterface::LoadPerformanceFile
void LoadPerformanceFile(int Caller, std::ifstream &InFile)
Load the performance file part of a sessionfile.
Definition: InterfaceUnit.cpp:17819
TInterface::CPCancelButtonClick
void __fastcall CPCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12486
TInterface::OutputLog4MouseDown
void __fastcall OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11201
TInterface::AddGraphic
@ AddGraphic
Definition: InterfaceUnit.h:885
TInterface::SetLevel1Mode
void SetLevel1Mode(int Caller)
Sets the Level1 user mode, using the Level1Mode variable to determine the mode.
Definition: InterfaceUnit.cpp:13068
TInterface::NewHomeButtonClick
void __fastcall NewHomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8882
TInterface::OutputLog4
TLabel * OutputLog4
Definition: InterfaceUnit.h:295
TInterface::FontDialog
TFontDialog * FontDialog
font change dialog
Definition: InterfaceUnit.h:496
TInterface::TrackSelecting
@ TrackSelecting
Definition: InterfaceUnit.h:886
TTrainController::TotLateArrMins
float TotLateArrMins
Definition: TrainUnit.h:758
TInterface::Level2PrefDirMode
enum TInterface::TLevel2PrefDirMode Level2PrefDirMode
TInterface::OperatingPanelLabel
TLabel * OperatingPanelLabel
displays 'Operation' or 'Disabled' on the operating panel during operation for running or paused
Definition: InterfaceUnit.h:323
TInterface::DivergingPointVectorPosition
int DivergingPointVectorPosition
Definition: InterfaceUnit.h:1077
TInterface::OAListBoxMouseUp
void __fastcall OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4781
TTrainController::PlotAllTrainsInZoomOutMode
void PlotAllTrainsInZoomOutMode(int Caller, bool Flash)
Plots all trains on screen in zoomed-out mode, state of 'Flash' determines whether the flashing train...
Definition: TrainUnit.cpp:14374
TInterface::SpeedButton108
TSpeedButton * SpeedButton108
Definition: InterfaceUnit.h:612
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1371
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:7761
TInterface::SavePerformanceFile
void SavePerformanceFile(int Caller, std::ofstream &OutFile)
Save performance file part of a session file.
Definition: InterfaceUnit.cpp:17874
TTextItem::Font
TFont * Font
the text font
Definition: TextUnit.h:52
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1525
TTrain::SignallerStopped
bool SignallerStopped
Definition: TrainUnit.h:432
TDisplay::SetFont
void SetFont(TFont *Font)
Set the screen font to 'Font'.
Definition: DisplayUnit.h:215
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:15955
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1515
TTrain::TrainDataEntryPtr
TTrainDataEntry * TrainDataEntryPtr
points to the current position in the timetable's TrainDataVector
Definition: TrainUnit.h:333
TInterface::TTLabel13
TLabel * TTLabel13
Definition: InterfaceUnit.h:350
TTrainDataEntry::StartSpeed
int StartSpeed
in km/h
Definition: TrainUnit.h:193
TTrainDataEntry::NumberOfTrains
int NumberOfTrains
number of repeats + 1
Definition: TrainUnit.h:189
TTrainController::Derailments
int Derailments
Definition: TrainUnit.h:764
clStationStopBackground
#define clStationStopBackground
Definition: GraphicUnit.h:301
TInterface::AZOrderButton
TButton * AZOrderButton
Definition: InterfaceUnit.h:140
TInterface::SpeedButton86
TSpeedButton * SpeedButton86
Definition: InterfaceUnit.h:590
TInterface::SpeedButton122
TSpeedButton * SpeedButton122
Definition: InterfaceUnit.h:626
Crossover
@ Crossover
Definition: TrackUnit.h:63
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:5620
TInterface::SpeedButton104
TSpeedButton * SpeedButton104
Definition: InterfaceUnit.h:608
TInterface::SignallerJoinedByMenuItem
TMenuItem * SignallerJoinedByMenuItem
Definition: InterfaceUnit.h:477
TRailGraphics::SpeedBut69NormBlackGlyph
Graphics::TBitmap * SpeedBut69NormBlackGlyph
Definition: GraphicUnit.h:1046
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:6609
TDisplay::ResetZoomInOffsets
void ResetZoomInOffsets()
Reset the zoomed-in screen display to the 'Home' position.
Definition: DisplayUnit.h:201
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9010
TInterface::RotRightMenuItem
TMenuItem * RotRightMenuItem
Definition: InterfaceUnit.h:475
AtLocation
@ AtLocation
Definition: TrainUnit.h:67
TInterface::ExportTTButton
TButton * ExportTTButton
Definition: InterfaceUnit.h:148
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
Signal
@ Signal
Definition: TrackUnit.h:73
TInterface::TimetableChangedFlag
bool TimetableChangedFlag
true when a timetable in the editor has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:997
TInterface::SaveTimetableToErrorFile
bool SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
Called when compiling the error log file, to save the loaded timetable if any and the timetable being...
Definition: InterfaceUnit.cpp:16882
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:682
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:16400
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:151
TInterface::TrainHeadCodeMenuItem
TMenuItem * TrainHeadCodeMenuItem
Definition: InterfaceUnit.h:459
TTrainController::TrainDataVector
TTrainDataVector TrainDataVector
vector containing the internal timetable
Definition: TrainUnit.h:805
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:11532
TAllRoutes::NotAutoSigsRoute
@ NotAutoSigsRoute
Definition: TrackUnit.h:1516
TTrain::ExitTimeHalf
TDateTime ExitTimeHalf
Definition: TrainUnit.h:414
Exited
@ Exited
Definition: TrainUnit.h:80
TInterface::OutputLog2
TLabel * OutputLog2
Definition: InterfaceUnit.h:293
TInterface::TTClockAdjustWarningLabel
TLabel * TTClockAdjustWarningLabel
Definition: InterfaceUnit.h:230
TInterface::SpeedButton74
TSpeedButton * SpeedButton74
Definition: InterfaceUnit.h:578
TInterface::ScreenRightButtonClick
void __fastcall ScreenRightButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8535
TInterface::PositionalPanel
TPanel * PositionalPanel
Definition: InterfaceUnit.h:384
TInterface::StepForwardMenuItemClick
void __fastcall StepForwardMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10345
TInterface::ErrorLog
void ErrorLog(int Caller, AnsiString Message)
The error logging routine, called when an error is detected.
Definition: InterfaceUnit.cpp:15748
TInterface::SpeedButton50
TSpeedButton * SpeedButton50
Definition: InterfaceUnit.h:554
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackElement.at(At)
Definition: TrackUnit.cpp:9511
TTrainController::LoadSessionTrains
void LoadSessionTrains(int Caller, std::ifstream &SessionFile)
load trains from a session file
Definition: TrainUnit.cpp:14071
TInterface::SpeedButton31
TSpeedButton * SpeedButton31
Definition: InterfaceUnit.h:535
TInterface::UserGraphicFoundFlag
bool UserGraphicFoundFlag
indicates that a user graphic item has been found when clicking on a build screen for moving
Definition: InterfaceUnit.h:995
TInterface::RouteCancelButtonClick
void __fastcall RouteCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2207
TInterface::SpeedButton91
TSpeedButton * SpeedButton91
Definition: InterfaceUnit.h:595
TInterface::SelectedTrainID
int SelectedTrainID
used to store the train ID when right clicked for signaller control actions
Definition: InterfaceUnit.h:1086
TInterface::SpeedButton113
TSpeedButton * SpeedButton113
Definition: InterfaceUnit.h:617
TInterface::SpeedButton82
TSpeedButton * SpeedButton82
Definition: InterfaceUnit.h:586
TTextHandler::SelectTextPtrAt
TTextItem * SelectTextPtrAt(int Caller, int At)
return the text item at position 'At' in SelectTextVector (carries out range checking)
Definition: TextUnit.cpp:542
TInterface::SpeedButton132
TSpeedButton * SpeedButton132
Definition: InterfaceUnit.h:636
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:687
TInterface::FlashingGraphics
void FlashingGraphics(int Caller, TDateTime Now)
Deal with any warning graphics that need to flash (call on, signal stop, crash etc),...
Definition: InterfaceUnit.cpp:15171
TInterface::ScreenLeftButton
TBitBtn * ScreenLeftButton
Definition: InterfaceUnit.h:250
TTrain::StoppedAtLocation
bool StoppedAtLocation
Definition: TrainUnit.h:432
TTrainController::TContinuationTrainExpectationMultiMapIterator
TContinuationTrainExpectationMultiMap::iterator TContinuationTrainExpectationMultiMapIterator
iterator for the multimap
Definition: TrainUnit.h:689
TInterface::TTClockx16ButtonClick
void __fastcall TTClockx16ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11869
TInterface::OAListBoxMouseDown
void __fastcall OAListBoxMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4838
TInterface::BuildTrackMenuItem
TMenuItem * BuildTrackMenuItem
Definition: InterfaceUnit.h:420
TInterface::SaveOperatingImageMenuItem
TMenuItem * SaveOperatingImageMenuItem
Definition: InterfaceUnit.h:454
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:731
TInterface::NoRailway
bool NoRailway()
Returns true if there are no track elements and no text.
Definition: InterfaceUnit.cpp:18616
TInterface::AllEntriesTTListBox
TListBox * AllEntriesTTListBox
the list of service entries displayed on the left hand side of the timetable edit screen
Definition: InterfaceUnit.h:404
TInterface::CallingOnButtonClick
void __fastcall CallingOnButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8445
TInterface::SaveTTDialog
TSaveDialog * SaveTTDialog
Definition: InterfaceUnit.h:495
TInterface::DeleteOnePrefDirButtonClick
void __fastcall DeleteOnePrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1967
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:3720
TAllRoutes::NextRouteID
int NextRouteID
stores the value for the route ID number that is next to be built
Definition: TrackUnit.h:1582
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:468
TInterface::TTEntryChangedFlag
bool TTEntryChangedFlag
true when a timetable entry that is displayed in the timetable entry edit window has changed
Definition: InterfaceUnit.h:1005
TInterface::HighlightPanel
TPanel * HighlightPanel
the orange bar that displays the current timetable entry in AllEntriesTTListBox
Definition: InterfaceUnit.h:370
TInterface::SpeedButton16
TSpeedButton * SpeedButton16
Definition: InterfaceUnit.h:520
TInterface::MoveTTEntryUpButtonClick
void __fastcall MoveTTEntryUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4285
TInterface::SpeedBottomLabel
TLabel * SpeedBottomLabel
Definition: InterfaceUnit.h:181
TTrainController::BFHigh
bool BFHigh
Definition: TrainUnit.h:743
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TInterface::TTClockResetButtonClick
void __fastcall TTClockResetButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12042
TInterface::ClockLabel
TLabel * ClockLabel
the timetable clock
Definition: InterfaceUnit.h:321
TInterface::SpeedButton43
TSpeedButton * SpeedButton43
Definition: InterfaceUnit.h:547
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:13129
TTrain::LagEntryPos
int LagEntryPos
Definition: TrainUnit.h:327
TInterface::SetTrackBuildImages
void SetTrackBuildImages(int Caller)
Sets the left screen images (track linked or not, gaps set or not, locations named or not) during rai...
Definition: InterfaceUnit.cpp:15985
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:3698
TInterface::AddText
@ AddText
Definition: InterfaceUnit.h:885
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2058
TTrainController::UnexpectedExits
int UnexpectedExits
Definition: TrainUnit.h:779
TInterface::LoadTimetableMenuItemClick
void __fastcall LoadTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9780
TInterface::LengthEditKeyUp
void __fastcall LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11655
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:11313
TInterface::OutputLog1
TLabel * OutputLog1
Definition: InterfaceUnit.h:292
TTrain::LeavingUnderSigControlAtContinuation
bool LeavingUnderSigControlAtContinuation
set when the train has reached an exit continuation when under signaller control, used to prevent the...
Definition: TrainUnit.h:355
TInterface::SpeedButton84
TSpeedButton * SpeedButton84
Definition: InterfaceUnit.h:588
TInterface::SpeedButton77
TSpeedButton * SpeedButton77
Definition: InterfaceUnit.h:581
TInterface::SpeedButton128
TSpeedButton * SpeedButton128
Definition: InterfaceUnit.h:632
TInterface::GetTrainFloatingInfoFromContinuation
void GetTrainFloatingInfoFromContinuation(int Caller, int VecPos, AnsiString FormatNoDPStr, AnsiString SpecialStr, AnsiString &TrainStatusFloat, AnsiString &TrainTTFloat)
Called when floating train info needed and train hasn't entered yet.
Definition: InterfaceUnit.cpp:14882
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:845
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5117
TInterface::AddSubMinsBox
TEdit * AddSubMinsBox
the edit box that accepts minutes to add or subtract
Definition: InterfaceUnit.h:175
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:17575
TInterface::TTClockExitButton
TButton * TTClockExitButton
Definition: InterfaceUnit.h:218
TInterface::SpeedEditBox2
TEdit * SpeedEditBox2
Definition: InterfaceUnit.h:101
TInterface::MoveForwardsMenuItemClick
void __fastcall MoveForwardsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10067
TTrack::Down
@ Down
Definition: TrackUnit.h:523
TTrainController::TwoOrMoreLocationsWarningGiven
bool TwoOrMoreLocationsWarningGiven
new at v2.6.0 to allow loops
Definition: TrainUnit.h:739
TInterface::TimetableNameLabel
TLabel * TimetableNameLabel
displays the current timetable name on the timetable edit panel
Definition: InterfaceUnit.h:311
TInterface::SpeedButton79
TSpeedButton * SpeedButton79
Definition: InterfaceUnit.h:583
TInterface::SpeedBottomLabel2
TLabel * SpeedBottomLabel2
Definition: InterfaceUnit.h:112
TInterface::SpeedButton51
TSpeedButton * SpeedButton51
Definition: InterfaceUnit.h:555
TInterface::IsPerformancePanelObscuringFloatingLabel
bool IsPerformancePanelObscuringFloatingLabel(int Caller)
Checked during operation, returns true if so and PerformancePanel removed - not used from v2....
Definition: InterfaceUnit.cpp:15828
TimeTimeLoc
@ TimeTimeLoc
Definition: TrainUnit.h:62
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1402
TInterface::TimetableChangedInAZOrderFlag
bool TimetableChangedInAZOrderFlag
used to give a warning message that changes will be discarded if proceed
Definition: InterfaceUnit.h:1001
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6318
TInterface::AddTrackButtonClick
void __fastcall AddTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:865
TInterface::SpeedButton92
TSpeedButton * SpeedButton92
Definition: InterfaceUnit.h:596
TInterface::DeleteMenuItemClick
void __fastcall DeleteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9638
TTrain::Derailed
bool Derailed
Definition: TrainUnit.h:432
TInterface::ConflictAnalysisButton
TButton * ConflictAnalysisButton
Definition: InterfaceUnit.h:233
TTextHandler::TextVectorPush
void TextVectorPush(int Caller, TTextItem Text)
push &Text onto TextVector & reset the size of the railway if necessary
Definition: TextUnit.cpp:485
TInterface::TTClockAdjButton
TBitBtn * TTClockAdjButton
Definition: InterfaceUnit.h:204
TInterface::PowerEditBoxKeyUp
void __fastcall PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11522
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:16045
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:6682
TTrainController::SaveSessionLockedRoutes
void SaveSessionLockedRoutes(int Caller, std::ofstream &SessionFile)
save locked routes to a session file
Definition: TrainUnit.cpp:14121
TInterface::OpenHelpMenuItemClick
void __fastcall OpenHelpMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11291
TTrain::OriginalPowerAtRail
double OriginalPowerAtRail
new at v2.4.0 to store value before a failure so it can be restored from here when repaired
Definition: TrainUnit.h:398
TInterface::CheckPerformanceFile
bool CheckPerformanceFile(int Caller, std::ifstream &InFile)
Check the performance file embedded within a session file & return false for error,...
Definition: InterfaceUnit.cpp:17843
TInterface::TInterface
__fastcall TInterface(TComponent *Owner)
constructor
Definition: InterfaceUnit.cpp:80
TInterface::SpeedButton15
TSpeedButton * SpeedButton15
Definition: InterfaceUnit.h:519
clB4G5R5
#define clB4G5R5
Definition: GraphicUnit.h:244
Timetable
@ Timetable
Definition: TrainUnit.h:56
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:123
TInterface
Definition: InterfaceUnit.h:56
TInterface::RemoveTrainMenuItemClick
void __fastcall RemoveTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10389
TInterface::RotRightMenuItemClick
void __fastcall RotRightMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9247
TTrain::AbleToMoveButForSignal
bool AbleToMoveButForSignal(int Caller)
Indicates that a train is only prevented from moving by a signal - used to allow appropriate popup me...
Definition: TrainUnit.cpp:6334
TTrainController::OpActionPanelVisible
bool OpActionPanelVisible
new v2.2.0 flag to prevent time to act functions when not visible
Definition: TrainUnit.h:737
TInterface::SaveInterface
void SaveInterface(int Caller, std::ofstream &SessionFile)
Save interface part of a session file.
Definition: InterfaceUnit.cpp:16469
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:530
TInterface::AcceptDragging
void __fastcall AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
Definition: InterfaceUnit.cpp:5587
Parapet
@ Parapet
Definition: TrackUnit.h:64
TTrack::GapFlashRedPosition
int GapFlashRedPosition
TrackVectorPosition of the gap element that is flashing green or red.
Definition: TrackUnit.h:673
HiddenDisplay
TDisplay * HiddenDisplay
The object pointer for the internal hidden display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:16070
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TInterface::RouteFlashDuration
float RouteFlashDuration
duration of the route flash period
Definition: InterfaceUnit.h:1043
TInterface::SpeedButton4
TSpeedButton * SpeedButton4
Definition: InterfaceUnit.h:508
TTrainController::SignalStopWarning
bool SignalStopWarning
Definition: TrainUnit.h:729
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:277
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8277
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:16020
TDisplay::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: DisplayUnit.cpp:447
TTrain::SignallerStopBrakeRate
double SignallerStopBrakeRate
the train brake rate when stopping under signaller control
Definition: TrainUnit.h:393
TTrainController::SignallerTrainRemovedOnAutoSigsRoute
bool SignallerTrainRemovedOnAutoSigsRoute
true if train was on an AutoSigsRoute when removed by the signaller
Definition: TrainUnit.h:735
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:710
TTrainController::MRSLow
bool MRSLow
Definition: TrainUnit.h:743
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:685
TTrain::Crashed
bool Crashed
Definition: TrainUnit.h:432
TInterface::SpeedButton44
TSpeedButton * SpeedButton44
Definition: InterfaceUnit.h:548
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:145
TInterface::ScreenRightButton
TBitBtn * ScreenRightButton
Definition: InterfaceUnit.h:249
TTrain::HeadCodePosition
Graphics::TBitmap * HeadCodePosition[4]
Set from the HeadCodeGrPtr[4] pointer values, HeadCodePosition[0] is always the front,...
Definition: TrainUnit.h:446
TInterface::OAListBox
TListBox * OAListBox
Operator action list, sits inside OperatorActionPanel and lists trains in ascending order of time to ...
Definition: InterfaceUnit.h:406
TTrain::TrainID
int TrainID
the train's identification number
Definition: TrainUnit.h:330
TInterface::SaveTTButton
TButton * SaveTTButton
Definition: InterfaceUnit.h:145
TUtilities::CheckStringDouble
bool CheckStringDouble(AnsiString &DoubleString)
checks the string represents a valid double value, returns true for success. Added at v2....
Definition: Utilities.cpp:327
TInterface::SpeedButton63
TSpeedButton * SpeedButton63
Definition: InterfaceUnit.h:567
TRailGraphics::bmLightBlueRect
Graphics::TBitmap * bmLightBlueRect
Definition: GraphicUnit.h:523
TInterface::NonSigRouteStartMarker
TGraphicElement * NonSigRouteStartMarker
Definition: InterfaceUnit.h:1124
clB3G3R3
#define clB3G3R3
Definition: GraphicUnit.h:186
TInterface::SpeedButton53
TSpeedButton * SpeedButton53
Definition: InterfaceUnit.h:557
TInterface::SpeedButton107
TSpeedButton * SpeedButton107
Definition: InterfaceUnit.h:611
TTrainController::TrainVectorAt
TTrain & TrainVectorAt(int Caller, int VecPos)
Return a reference to the train at position VecPos in the TrainVector, carries out range checking on ...
Definition: TrainUnit.cpp:14397
TInterface::EditMenuClick
void __fastcall EditMenuClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8910
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:135
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:11240
TInterface::ModeMenu
TMenuItem * ModeMenu
Definition: InterfaceUnit.h:419
TInterface::SpeedButton112
TSpeedButton * SpeedButton112
Definition: InterfaceUnit.h:616
TInterface::MTBFEditBoxClick
void __fastcall MTBFEditBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12352
TInterface::TEVPtr
TTEVPtr TEVPtr
Definition: InterfaceUnit.h:1147
TInterface::MasterClock
TTimer * MasterClock
the program clock (not the timetable clock)
Definition: InterfaceUnit.h:499
TInterface::OutputLog6MouseDown
void __fastcall OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11220
TRailGraphics::SpeedBut70GrndBlackGlyph
Graphics::TBitmap * SpeedBut70GrndBlackGlyph
Definition: GraphicUnit.h:1055
TTrainController::NumFailures
int NumFailures
Definition: TrainUnit.h:780
TInterface::CreateEditTTTitle
AnsiString CreateEditTTTitle
the title of the timetable currently being edited - i.e. the filename without the '....
Definition: InterfaceUnit.h:906
TInterface::AboutMenuItemClick
void __fastcall AboutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11270
TInterface::SelectStartPair
THVPair SelectStartPair
'Select' menu items
Definition: InterfaceUnit.h:1126
TTrainController::TOpTimeToActMultiMapIterator
TOpTimeToActMultiMap::iterator TOpTimeToActMultiMapIterator
Definition: TrainUnit.h:721
TInterface::SpeedButton6
TSpeedButton * SpeedButton6
Definition: InterfaceUnit.h:510
TTrack
Definition: TrackUnit.h:463
TInterface::OperatorActionPanelStartDrag
void __fastcall OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5662
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:757
TInterface::OperateRailwayMenuItem
TMenuItem * OperateRailwayMenuItem
Definition: InterfaceUnit.h:424
TInterface::SaveRailwayTBPButton
TBitBtn * SaveRailwayTBPButton
Save button on TrackBuildPanel.
Definition: InterfaceUnit.h:73
TTrain::ExitSpeedFull
double ExitSpeedFull
speed when leaving the next element
Definition: TrainUnit.h:381
TInterface::MTBFLabel
TLabel * MTBFLabel
Definition: InterfaceUnit.h:482
TInterface::SelectBitmap
Graphics::TBitmap * SelectBitmap
the graphic defined by Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1048
TInterface::PreventGapOffsetResetting
bool PreventGapOffsetResetting
during gap setting gaps are highlighted in turn for the user to select the matching gap,...
Definition: InterfaceUnit.h:967
TInterface::TakeSignallerControlMenuItem
TMenuItem * TakeSignallerControlMenuItem
Definition: InterfaceUnit.h:460
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TInterface::Pasting
@ Pasting
Definition: InterfaceUnit.h:886
TInterface::AddTextButton
TBitBtn * AddTextButton
Definition: InterfaceUnit.h:66
TInterface::LoadRailwayMenuItem
TMenuItem * LoadRailwayMenuItem
Definition: InterfaceUnit.h:410
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TInterface::CrashImage
TImage * CrashImage
Definition: InterfaceUnit.h:263
TTrainController::RandomFailureCounter
unsigned int RandomFailureCounter
new at v2.4.0, resets after 53 seconds (53 prime so can trigger at any clock time)
Definition: TrainUnit.h:795
TInterface::SpeedButton123
TSpeedButton * SpeedButton123
Definition: InterfaceUnit.h:627
TInterface::USERGRAPHICS_DIR_NAME
static const UnicodeString USERGRAPHICS_DIR_NAME
Definition: InterfaceUnit.h:872
TInterface::mbLeftDown
bool mbLeftDown
true when the left mouse button is down
Definition: InterfaceUnit.h:955
TInterface::SpeedButton115
TSpeedButton * SpeedButton115
Definition: InterfaceUnit.h:619
TInterface::ProgramVersion
UnicodeString ProgramVersion
Definition: InterfaceUnit.h:858
TInterface::TTClockResetButton
TButton * TTClockResetButton
Definition: InterfaceUnit.h:219
TUtilities::CheckAndReadFileInt
bool CheckAndReadFileInt(std::ifstream &InFile, int Lowest, int Highest, int &OutInt)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success ...
Definition: Utilities.cpp:251
TInterface::TempCursor
TCursor TempCursor
stores the screen cursor while a temporary cursor (ususlly an hourglass) is displayed
Definition: InterfaceUnit.h:1113
Interface
TInterface * Interface
Definition: InterfaceUnit.cpp:67
TInterface::SpeedButton61
TSpeedButton * SpeedButton61
Definition: InterfaceUnit.h:565
TDisplay::HideWarningLog
void HideWarningLog(int Caller)
Hide all the warnings from the top part of the screen - for timetable clock adjustment.
Definition: DisplayUnit.cpp:475
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:126
TUtilities::DecimalPoint
char DecimalPoint
added at v2.4.0 so can use the local value in loaded session files
Definition: Utilities.h:45
TInterface::ConstructPrefDir
TOnePrefDir * ConstructPrefDir
the Pref Dir under construction
Definition: InterfaceUnit.h:1133
TInterface::SpeedButton81
TSpeedButton * SpeedButton81
Definition: InterfaceUnit.h:585
TInterface::SigsOnLeftImage1
TImage * SigsOnLeftImage1
Definition: InterfaceUnit.h:280
TInterface::BuildTrackMenuItemClick
void __fastcall BuildTrackMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:848
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2583
TInterface::ClearandRebuildRailway
void ClearandRebuildRailway(int Caller)
Clear screen and rebuild it from stored data, uses HiddenScreen to avoid flicker.
Definition: InterfaceUnit.cpp:12570
TInterface::DisplayOneTTLineInPanel
void DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
Display a line from the TimetableEditVector (consists of a series of AnsiStrings, each of which repre...
Definition: InterfaceUnit.cpp:5367
TInterface::PlanPrefDirsMenuItem
TMenuItem * PlanPrefDirsMenuItem
Definition: InterfaceUnit.h:421
TInterface::AreAnyTimesInCurrentEntry
bool AreAnyTimesInCurrentEntry()
Search the timetable entry pointed to by TTCurrentEntryPtr and if any times (HH:MM) are present retur...
Definition: InterfaceUnit.cpp:5447
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:7978
TInterface::AutoRouteStartMarker
TGraphicElement * AutoRouteStartMarker
Definition: InterfaceUnit.h:1124
TInterface::RestoreTTButtonClick
void __fastcall RestoreTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4446
TInterface::SaveTTButtonClick
void __fastcall SaveTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4064
TInterface::FormCreate
void __fastcall FormCreate(TObject *Sender)
Definition: InterfaceUnit.cpp:744
TGraphicElement::SetSourceRect
void SetSourceRect(int Left, int Top)
Set SourceRect member values from those supplied and existing Width & Height - ensure this is only ca...
Definition: TrackUnit.h:373
TTrack::SelectPush
void SelectPush(TTrackElement TrackElement)
Store a TrackElement in the SelectVector.
Definition: TrackUnit.h:824
TAllRoutes::SignallerRemovedTrainAutoRoute
TOneRoute SignallerRemovedTrainAutoRoute
if train was on an AutoSigsRoute when removed then this stores the route so that signals can be reset
Definition: TrackUnit.h:1588
TInterface::SpeedButton7
TSpeedButton * SpeedButton7
Definition: InterfaceUnit.h:511
TTrainController::MassHigh
bool MassHigh
Definition: TrainUnit.h:743
TInterface::TimetablePanel
TPanel * TimetablePanel
'Create a timetable'/'Edit a timetable' panel that contains the topmost buttons (show/hide & exit)
Definition: InterfaceUnit.h:361
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:1823
TTrain::PlotTrainWithNewBackgroundColour
void PlotTrainWithNewBackgroundColour(int Caller, TColor NewBackgroundColour, TDisplay *Disp)
Changes the train's background colour (e.g. to pale green if stopped at a station) Note that this use...
Definition: TrainUnit.cpp:3264
TInterface::LoadSessionMenuItem
TMenuItem * LoadSessionMenuItem
Definition: InterfaceUnit.h:414
TInterface::SpeedButton69
TSpeedButton * SpeedButton69
Definition: InterfaceUnit.h:573
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:131
TInterface::OutputLog5MouseDown
void __fastcall OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11211
TInterface::ErrorButton
TBitBtn * ErrorButton
the 'Press to exit' button on the error screen
Definition: InterfaceUnit.h:257
TInterface::SpeedButton24
TSpeedButton * SpeedButton24
Definition: InterfaceUnit.h:528
TInterface::WarningFlash
bool WarningFlash
toggles on and off automatically at a cycle of about 0.5 sec, used to drive the warning icons during ...
Definition: InterfaceUnit.h:1007
TInterface::CurrentSpeedButton
TSpeedButton * CurrentSpeedButton
stores the selected track build element button during railway building
Definition: InterfaceUnit.h:1144
TInterface::MainScreenMouseDown
void __fastcall MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:5683
TTrain::ExitTimeFull
TDateTime ExitTimeFull
times used in SetTrainMovementValues corresponding to the next element the train runs on
Definition: TrainUnit.h:414
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:156
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:693
TInterface::TotalTicks
unsigned int TotalTicks
total clock ticks
Definition: InterfaceUnit.h:1054
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2268
TInterface::SpeedTopLabel2
TLabel * SpeedTopLabel2
Definition: InterfaceUnit.h:111
SignallerChangeDirection
@ SignallerChangeDirection
Definition: TrainUnit.h:51
TRailGraphics::GridBitmap
Graphics::TBitmap * GridBitmap
Definition: GraphicUnit.h:900
TInterface::PowerBottomLabel
TLabel * PowerBottomLabel
Definition: InterfaceUnit.h:189
TInterface::PasteMenuItem
TMenuItem * PasteMenuItem
Definition: InterfaceUnit.h:437
TTextHandler::EnterAndDisplayNewText
void EnterAndDisplayNewText(int Caller, TTextItem Text, int HPos, int VPos)
add Text to TextVector and display it on the screen
Definition: TextUnit.cpp:179
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:11028
TInterface::CreateEditTTFileName
AnsiString CreateEditTTFileName
the full path and filename of the timetable file
Definition: InterfaceUnit.h:904
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:11785
TInterface::PerformanceLogButtonClick
void __fastcall PerformanceLogButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2229
TTrainController::CheckSessionContinuationAutoSigEntries
bool CheckSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for ContinuationAutoSigEntries, true for success.
Definition: TrainUnit.cpp:14243
IDInt
Definition: TrackUnit.h:412
TInterface::SelectLengthsMenuItemClick
void __fastcall SelectLengthsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9657
TInterface::NewSelectBitmapHLoc
int NewSelectBitmapHLoc
the new (during & at end of moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1062
TInterface::LoadUserGraphic
void LoadUserGraphic(int Caller)
Load a user-defined graphic (bmp, gif, jpg, png).
Definition: InterfaceUnit.cpp:18843
TInterface::TTCurrentEntryPtr
TTEVPtr TTCurrentEntryPtr
Definition: InterfaceUnit.h:1147
TRunningEntry
TRunningEntry
contains status info for each train
Definition: TrainUnit.h:79
TInterface::OutputLog6
TLabel * OutputLog6
Definition: InterfaceUnit.h:297
TUtilities
Definition: Utilities.h:36
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:3967
TInterface::CreateTimetableMenuItemClick
void __fastcall CreateTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3102
TInterface::ExportTTButtonClick
void __fastcall ExportTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4529
TDisplay
Definition: DisplayUnit.h:48
TInterface::SpeedButton9
TSpeedButton * SpeedButton9
Definition: InterfaceUnit.h:513
TInterface::TTClockxEighthButtonClick
void __fastcall TTClockxEighthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11945
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:9258
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:143
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:797
TInterface::Text_X
int Text_X
the 'X' pixel value for an item of text
Definition: InterfaceUnit.h:1096
TInterface::SpeedVariableLabel
TLabel * SpeedVariableLabel
Definition: InterfaceUnit.h:182
TInterface::SpeedButton49
TSpeedButton * SpeedButton49
Definition: InterfaceUnit.h:553
TInterface::SigPrefNonConsecButton
TBitBtn * SigPrefNonConsecButton
Definition: InterfaceUnit.h:654
TTrain::StoppedWithoutPower
bool StoppedWithoutPower
Definition: TrainUnit.h:433
TInterface::GetTrainStatusFloat
AnsiString GetTrainStatusFloat(int Caller, int TrainID, AnsiString FormatNoDPStr, AnsiString SpecialStr)
used for floating window to display train status
Definition: InterfaceUnit.cpp:14964
TInterface::PowerVariableLabel
TLabel * PowerVariableLabel
Definition: InterfaceUnit.h:190
TActionEventType
TActionEventType
Used for reporting error conditions & warnings.
Definition: TrainUnit.h:39
TInterface::GapsNotSetImage
TImage * GapsNotSetImage
Definition: InterfaceUnit.h:277
TInterface::Level1Mode
enum TInterface::TLevel1Mode Level1Mode
TInterface::CallLogTickerLabel
TLabel * CallLogTickerLabel
diagnostic label displaying the call log depth, made visible by ctrl+ alt+ 2
Definition: InterfaceUnit.h:319
TInterface::TimetableEditVector
TTimetableEditVector TimetableEditVector
Definition: InterfaceUnit.h:1150
TTrainController::TrainExistsAtIdent
bool TrainExistsAtIdent(int Caller, int TrainID)
new at v2.4.0 return true if find the train (added at v2.4.0 as can select a removed train in OAListB...
Definition: TrainUnit.cpp:8678
SignallerJoin
@ SignallerJoin
Definition: TrainUnit.h:50
TTrain::StepForwardFlag
bool StepForwardFlag
set when the signaller command to step forward one element has been given
Definition: TrainUnit.h:365
TInterface::SaveRailwayDialog
TSaveDialog * SaveRailwayDialog
Definition: InterfaceUnit.h:494
TInterface::TTClockAdjustWarningPanel
TPanel * TTClockAdjustWarningPanel
Definition: InterfaceUnit.h:213
TInterface::TrainTTInfoOnOffMenuItemClick
void __fastcall TrainTTInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5562
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:95
TTrainController::Operate
void Operate(int Caller)
called every clock tick to introduce new trains and update existing trains
Definition: TrainUnit.cpp:7990
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:151
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:886
TTrain::PowerAtRail
double PowerAtRail
in Watts (taken as 80% of the train's Gross Power, i.e. that entered by the user)
Definition: TrainUnit.h:396
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:671
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:12921
TAllRoutes::LevelCrossingBarrierDownDelay
const float LevelCrossingBarrierDownDelay
the full value in seconds for which the level crossing flashes prior to opening to trains
Definition: TrackUnit.h:1576
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1569
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:154
TInterface::SetSaveMenuAndButtons
void SetSaveMenuAndButtons(int Caller)
Called during the ClockTimer2 function to set screen boundaries, buttons & menu items.
Definition: InterfaceUnit.cpp:15453
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TInterface::TIMETABLE_DIR_NAME
static const UnicodeString TIMETABLE_DIR_NAME
Definition: InterfaceUnit.h:867
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:128
TInterface::SaveImageAndPrefDirsMenuItem
TMenuItem * SaveImageAndPrefDirsMenuItem
Definition: InterfaceUnit.h:453
TInterface::LoadRailwayMenuItemClick
void __fastcall LoadRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2314
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6926
TInterface::FormKeyUp
void __fastcall FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11161
TInterface::CopyTTEntryKeyFlag
bool CopyTTEntryKeyFlag
Definition: InterfaceUnit.h:1022
TTrainDataEntry::TrainOperatingDataVector
TTrainOperatingDataVector TrainOperatingDataVector
operating information for the train including all its repeats
Definition: TrainUnit.h:197
TInterface::OutputLog9MouseDown
void __fastcall OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11250
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:544
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:145
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:791
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1388
TInterface::SpeedButton80
TSpeedButton * SpeedButton80
Definition: InterfaceUnit.h:584
TTrain::IsThereAnAdjacentTrain
bool IsThereAnAdjacentTrain(int Caller, TTrain *&TrainToBeJoinedBy)
Definition: TrainUnit.cpp:4713
TInterface::ApproachLocking
void ApproachLocking(int Caller, TDateTime Now)
Function that deals with approach locking during ClockTimer2 function.
Definition: InterfaceUnit.cpp:14353
TInterface::TimetableTitle
AnsiString TimetableTitle
the titles of the loaded railway and loaded timetable, i.e. the filenames without the extension
Definition: InterfaceUnit.h:918
TInterface::BlackBgndMenuItemClick
void __fastcall BlackBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11314
TInterface::SpeedButton114
TSpeedButton * SpeedButton114
Definition: InterfaceUnit.h:618
TInterface::Deleting
@ Deleting
Definition: InterfaceUnit.h:886
TInterface::RestoreAllDefaultLengthsButton
TBitBtn * RestoreAllDefaultLengthsButton
Definition: InterfaceUnit.h:77
TInterface::ClearAllMenuItemClick
void __fastcall ClearAllMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3031
TUtilities::EventLog
std::deque< AnsiString > EventLog
event store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:57
TInterface::MoveTTEntryUpKeyFlag
bool MoveTTEntryUpKeyFlag
Definition: InterfaceUnit.h:1020
TActionVectorEntry::FormatType
TTimetableFormatType FormatType
defines the timetable action type
Definition: TrainUnit.h:110
TInterface::TextBox
TEdit * TextBox
the edit box that accepts text to be added
Definition: InterfaceUnit.h:88
TGraphicElement::GetHPos
int GetHPos()
Definition: TrackUnit.h:362
TInterface::SpeedButton133
TSpeedButton * SpeedButton133
Definition: InterfaceUnit.h:637
TOnePrefDir::SearchVectorSize
unsigned int SearchVectorSize() const
Return the vector size.
Definition: TrackUnit.h:1281
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:644
TTrainController::TimetableStartTime
TDateTime TimetableStartTime
the start time of the current timetable
Definition: TrainUnit.h:642
TTrainController::UnplotTrains
void UnplotTrains(int Caller)
unplot all trains from screen
Definition: TrainUnit.cpp:8333
TInterface::SpeedButton18
TSpeedButton * SpeedButton18
Definition: InterfaceUnit.h:522
TInterface::ScreenGridFlag
bool ScreenGridFlag
true when the screen grid is displayed
Definition: InterfaceUnit.h:975
TInterface::InfoCaptionStore
AnsiString InfoCaptionStore
temporary store for the information panel caption
Definition: InterfaceUnit.h:912
TRailGraphics::smBrightGreen
Graphics::TBitmap * smBrightGreen
Definition: GraphicUnit.h:878
TInterface::CopiedEntryFlag
bool CopiedEntryFlag
true when CopiedEntryStr holds a timetable entry in the timetable editor
Definition: InterfaceUnit.h:935
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:14040
TInterface::SpeedButton89
TSpeedButton * SpeedButton89
Definition: InterfaceUnit.h:593
TTrainController::EarlyArrivals
int EarlyArrivals
Definition: TrainUnit.h:765
TInterface::AnyTTKeyFlagSet
bool AnyTTKeyFlagSet()
Definition: InterfaceUnit.h:1160
TTrainController::CreateFormattedTimetable
void CreateFormattedTimetable(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir)
Examines the internal timetable (TrainDataVector) and creates from it a chronological (....
Definition: TrainUnit.cpp:14410
TInterface::SetTopIndex
void SetTopIndex(int Caller)
This used in timetable functions when shift keys pressed to make sure that the highlighted entry rema...
Definition: InterfaceUnit.cpp:12548
TTrack::RouteFlashFlag
bool RouteFlashFlag
true while a route is flashing prior to being set
Definition: TrackUnit.h:660
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:12244
TInterface::PowerToggleButtonClick
void __fastcall PowerToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11501
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1186
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:149
TInterface::SpeedButton46
TSpeedButton * SpeedButton46
Definition: InterfaceUnit.h:550
Points
@ Points
Definition: TrackUnit.h:63
TTrainController::TotLatePassMins
float TotLatePassMins
Definition: TrainUnit.h:760
TTrainController::StripSpaces
void StripSpaces(int Caller, AnsiString &Input)
Strip both leading and trailing spaces at ends of Input and spaces before and after all commas and se...
Definition: TrainUnit.cpp:12807
TInterface::Delay
void Delay(int Caller, double Msec)
Delays operation for the set time in milliseconds.
Definition: InterfaceUnit.cpp:12953
TTrain::JoinedOtherTrainFlag
bool JoinedOtherTrainFlag
true when the train has joined another train following an 'Fjo' timetable command or a signaller join...
Definition: TrainUnit.h:351
TTrainController::OpActionPanelHintDelayCounter
unsigned int OpActionPanelHintDelayCounter
new v2.2.0 on start operation delays the op action panel headcode display for about 3 secs while hint...
Definition: TrainUnit.h:793
TTrainController::BFLow
bool BFLow
Definition: TrainUnit.h:743
TInterface::OutputLog7
TLabel * OutputLog7
Definition: InterfaceUnit.h:298
TTrainController::TotArrDepPass
int TotArrDepPass
Definition: TrainUnit.h:778
TInterface::LastNonCtrlOrShiftKeyDown
int LastNonCtrlOrShiftKeyDown
value of last key (other than Ctrl or Shift) pressed down - to prevent repeated FormKeyDown calls fro...
Definition: InterfaceUnit.h:1060
SignallerPassRedSignal
@ SignallerPassRedSignal
Definition: TrainUnit.h:51
TRailGraphics::ChangeForegroundColour
void ChangeForegroundColour(int Caller, Graphics::TBitmap *BitmapIn, Graphics::TBitmap *BitmapOut, TColor NewForegroundColour, TColor BackgroundColour)
Definition: GraphicUnit.cpp:3326
TInterface::TextItem
int TextItem
used to store a single item of text
Definition: InterfaceUnit.h:1102
TInterface::UserGraphicButtonClick
void __fastcall UserGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12374
TInterface::OriginalTimetableEditVector
TTimetableEditVector OriginalTimetableEditVector
the complete timetable as a list of AnsiStrings for use in edit timetable functions
Definition: InterfaceUnit.h:1150
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1569
TInterface::PresetAutoSigRoutesButtonClick
void __fastcall PresetAutoSigRoutesButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12083
TInterface::SigPrefNonConsecButtonClick
void __fastcall SigPrefNonConsecButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2130
TRailGraphics::SpeedBut68GrndBlackGlyph
Graphics::TBitmap * SpeedBut68GrndBlackGlyph
Definition: GraphicUnit.h:1053
TTrain::SignallerRemoved
bool SignallerRemoved
set when removed under signaller control to force a removal from the display at the next clock tick
Definition: TrainUnit.h:359
TTrain::FrontCodePtr
Graphics::TBitmap * FrontCodePtr
points to the front headcode segment, this is set to red or blue depending on TrainMode
Definition: TrainUnit.h:450
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:15377
Continuation
@ Continuation
Definition: TrackUnit.h:63
TInterface::ScreenUpButton
TBitBtn * ScreenUpButton
Definition: InterfaceUnit.h:251
TInterface::TTServiceSyntaxCheckButton
TButton * TTServiceSyntaxCheckButton
Definition: InterfaceUnit.h:143
TTrainController::CallOnWarning
bool CallOnWarning
Definition: TrainUnit.h:729
TInterface::SetLengthsButton
TBitBtn * SetLengthsButton
Definition: InterfaceUnit.h:71
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
GraphicUnit.h
TInterface::AppActivate
void __fastcall AppActivate(TObject *Sender)
Definition: InterfaceUnit.cpp:795
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3328
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5353
TInterface::AddTextButtonClick
void __fastcall AddTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1056
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TInterface::ReselectMenuItemClick
void __fastcall ReselectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8958
TInterface::SpeedButton94
TSpeedButton * SpeedButton94
Definition: InterfaceUnit.h:598
TInterface::SaveTTAsKeyFlag
bool SaveTTAsKeyFlag
Definition: InterfaceUnit.h:1031
TInterface::SaveTTEntryButtonClick
void __fastcall SaveTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3916
TInterface::TimetablePanelLabel
TLabel * TimetablePanelLabel
label to the left of TimetablePanel
Definition: InterfaceUnit.h:313
TTrack::PointFlashFlag
bool PointFlashFlag
true when points are flashing during manual change
Definition: TrackUnit.h:658
TTrainController::OnTimeDeps
int OnTimeDeps
Definition: TrainUnit.h:773
TTrain::RestoreTimetableLocation
AnsiString RestoreTimetableLocation
stores the location name at which signaller control is taken, to ensure that it is back at that locat...
Definition: TrainUnit.h:424
TInterface::SpeedButton40
TSpeedButton * SpeedButton40
Definition: InterfaceUnit.h:544
TTrainController::TimetableIntegrityCheck
bool TimetableIntegrityCheck(int Caller, char *FileName, bool GiveMessages, bool CheckLocationsExistInRailway)
Checks overall timetable integrity, calls many other specific checking functions, returns true for su...
Definition: TrainUnit.cpp:9026
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TDisplay::Left
int Left()
Return the left pixel position of the screen.
Definition: DisplayUnit.h:114
TTrain::SignallerMaxSpeed
int SignallerMaxSpeed
maximum train speed under signaller control (in km/h)
Definition: TrainUnit.h:323
TInterface::BufferAttentionImage
TImage * BufferAttentionImage
Definition: InterfaceUnit.h:261
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:11071
TTrainController::SendPerformanceSummary
void SendPerformanceSummary(int Caller, std::ofstream &PerfFile)
At the end of operation a summary of overall performance is sent to the performance file by this func...
Definition: TrainUnit.cpp:17018
TInterface::OperatorActionButtonClick
void __fastcall OperatorActionButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12186
TInterface::SpeedEditBox
TEdit * SpeedEditBox
Definition: InterfaceUnit.h:179
TInterface::LoadRailwayDialog
TOpenDialog * LoadRailwayDialog
Definition: InterfaceUnit.h:488
TInterface::CopyMenuItem
TMenuItem * CopyMenuItem
Definition: InterfaceUnit.h:433
TInterface::ResetDefaultLengthButtonClick
void __fastcall ResetDefaultLengthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1566
RepairFailedTrain
@ RepairFailedTrain
Definition: TrainUnit.h:51
TInterface::NoOperMode
@ NoOperMode
Definition: InterfaceUnit.h:877
TInterface::ErrorLogCalledFlag
bool ErrorLogCalledFlag
true when an error has been thrown, stops repeated calls to ErrorLog and stops the MasterClockTimer f...
Definition: InterfaceUnit.h:943
TInterface::NextTTEntryKeyFlag
bool NextTTEntryKeyFlag
Definition: InterfaceUnit.h:1019
TInterface::RouteFlashStartTime
TDateTime RouteFlashStartTime
stores the starting time (timetable clock time) for route flashing
Definition: InterfaceUnit.h:1120
TInterface::PerformancePanelLabel
TLabel * PerformancePanelLabel
label at the top of PerformancePanel
Definition: InterfaceUnit.h:303
TInterface::BlueBgndMenuItemClick
void __fastcall BlueBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11366
TInterface::SetTrackLengths
void SetTrackLengths(int Caller, int Distance, int SpeedLimit)
Called during track building when setting distances, to calculate and set the individual track elemen...
Definition: InterfaceUnit.cpp:18284
TInterface::SpeedToggleButtonClick
void __fastcall SpeedToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11392
TTrainController::ContinuationEntryFloatingTTString
AnsiString ContinuationEntryFloatingTTString(int Caller, TTrainDataEntry *TTDEPtr, int RepeatNumber, int IncrementalMinutes, int IncrementalDigits)
Build string for use in floating window for expected trains at continuations.
Definition: TrainUnit.cpp:8709
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:2945
TGraphicElement::GetVPos
int GetVPos()
Definition: TrackUnit.h:367
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1405
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:85
TTrain::SPADFlag
bool SPADFlag
set when running past a red signal without permission flags to indicate relevant stop conditions or p...
Definition: TrainUnit.h:430
TInterface::TTLabel5
TLabel * TTLabel5
Definition: InterfaceUnit.h:343
TInterface::HomeButtonClick
void __fastcall HomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8841
TInterface::PointFlashStartTime
TDateTime PointFlashStartTime
stores the starting time (timetable clock time) for points flashing
Definition: InterfaceUnit.h:1118
TInterface::TTLabel7
TLabel * TTLabel7
Definition: InterfaceUnit.h:345
TInterface::RailwayWebSiteMenuItemClick
void __fastcall RailwayWebSiteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11306
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:614
TInterface::SpeedButton36
TSpeedButton * SpeedButton36
Definition: InterfaceUnit.h:540
TInterface::TTFirstServicePtr
TTEVPtr TTFirstServicePtr
Definition: InterfaceUnit.h:1147
TInterface::ClockTimer2
void ClockTimer2(int Caller)
The main loop, called every clock tick via MasterClockTimer.
Definition: InterfaceUnit.cpp:7840
TInterface::SpeedButton56
TSpeedButton * SpeedButton56
Definition: InterfaceUnit.h:560
TDisplay::PlotDashedRect
void PlotDashedRect(int Caller, TRect Rect)
Plot a dashed rectangle for the area defined by Rect, used when selecting display areas.
Definition: DisplayUnit.cpp:429
TInterface::NewTTEntryButtonClick
void __fastcall NewTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3491
TInterface::LoadSessionMenuItemClick
void __fastcall LoadSessionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3017
TTrack::SelectVectorClear
void SelectVectorClear()
Definition: TrackUnit.h:829
TInterface::PerformanceFileName
AnsiString PerformanceFileName
full path and filename of the performance file
Definition: InterfaceUnit.h:916
TInterface::AutoSigsButton
TBitBtn * AutoSigsButton
Definition: InterfaceUnit.h:195
TInterface::PopupMenu
TPopupMenu * PopupMenu
Definition: InterfaceUnit.h:485
TInterface::LoadSessionFlag
bool LoadSessionFlag
true when a session load command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:953
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:271
TInterface::NoTrackMode
@ NoTrackMode
Definition: InterfaceUnit.h:885
TInterface::TimetableValidFlag
bool TimetableValidFlag
indicates that a 'Validate timetable' button click in the timetable editor has succeeded
Definition: InterfaceUnit.h:999
TInterface::TimetableControlMenuItem
TMenuItem * TimetableControlMenuItem
Definition: InterfaceUnit.h:461
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:294
TUtilities::PerformanceFile
std::ofstream PerformanceFile
the file where the performance log for a particular period of operation is saved
Definition: Utilities.h:53
TInterface::TTLabel15
TLabel * TTLabel15
Definition: InterfaceUnit.h:352
TInterface::PreferredRoute
bool PreferredRoute
true when AutoSig or preferred route building selected during operation (always same state as ConsecS...
Definition: InterfaceUnit.h:963
TInterface::ConvertCRLFsToCommas
void ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
Used in timetable editing functions to convert any CRLFs in intended service entries to commas.
Definition: InterfaceUnit.cpp:5148
TInterface::OutputLog2MouseDown
void __fastcall OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11182
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
TInterface::SpeedButton106
TSpeedButton * SpeedButton106
Definition: InterfaceUnit.h:610
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TInterface::LoadTimetableFromSessionFile
bool LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Loads timetable into memory from a session file, true if successful.
Definition: InterfaceUnit.cpp:16934
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:677
TInterface::SpeedButton125
TSpeedButton * SpeedButton125
Definition: InterfaceUnit.h:629
TInterface::SpeedButton21
TSpeedButton * SpeedButton21
Definition: InterfaceUnit.h:525
TUtilities::DateTimeStamp
AnsiString DateTimeStamp()
creates a string of the form 'dd/mm/yyyy hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:67
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:785
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4216
TInterface::SpeedButton64
TSpeedButton * SpeedButton64
Definition: InterfaceUnit.h:568
TInterface::AllEntriesTTListBoxMouseUp
void __fastcall AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4728
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1596
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:7808
TInterface::FontButton
TBitBtn * FontButton
Definition: InterfaceUnit.h:69
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:121
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:697
TInterface::NextTTEntryButtonClick
void __fastcall NextTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3413
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:198
TInterface::~TInterface
__fastcall ~TInterface()
destructor
Definition: InterfaceUnit.cpp:685
TInterface::CancelTTEntryButtonClick
void __fastcall CancelTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4409
TInterface::TTEVPtr
std::vector< AnsiString >::iterator TTEVPtr
typedef for pointers to entries in edit timetable functions
Definition: InterfaceUnit.h:896
TInterface::SaveHeaderMenu1Click
void __fastcall SaveHeaderMenu1Click(TObject *Sender)
Definition: InterfaceUnit.cpp:2959
TInterface::TTStartTimePtr
TTEVPtr TTStartTimePtr
Definition: InterfaceUnit.h:1147
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:618
TInterface::TTClockAdjPanel
TPanel * TTClockAdjPanel
Definition: InterfaceUnit.h:212
TInterface::BuildTrainDataVectorForLoadFile
bool BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
Convert a stored timetable file (either as a stand alone file or within a session file) to a loaded t...
Definition: InterfaceUnit.cpp:17145
TInterface::ConflictPanel
TPanel * ConflictPanel
Definition: InterfaceUnit.h:236
TInterface::CompileAllEntriesMemoAndSetPointers
void CompileAllEntriesMemoAndSetPointers(int Caller)
Used during timetable editing funtions to compile the list of entries into the left hand long entry w...
Definition: InterfaceUnit.cpp:4903
TInterface::CopiedEntryStr
AnsiString CopiedEntryStr
a timetable entry that has been copied
Definition: InterfaceUnit.h:902
TInterface::SpeedButton12
TSpeedButton * SpeedButton12
Definition: InterfaceUnit.h:516
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:17559
TInterface::SelectMenuItem
TMenuItem * SelectMenuItem
Definition: InterfaceUnit.h:430
TInterface::MoveTTEntryDownKeyFlag
bool MoveTTEntryDownKeyFlag
Definition: InterfaceUnit.h:1021
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1579
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4201
Connection
@ Connection
Definition: TrackUnit.h:73
TInterface::TTTextButtonClick
void __fastcall TTTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4568
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3305
TTrainController::TrainFailedWarning
bool TrainFailedWarning
Flags to enable the relevant warning graphics to flash at the left hand side of the screen.
Definition: TrainUnit.h:729
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1571
TInterface::LengthOKButton
TBitBtn * LengthOKButton
distance/speed setting buttons - left to right & top to bottom
Definition: InterfaceUnit.h:80
TTrain::NextTrainID
static int NextTrainID
the ID value to be used for the next train that is created, static so that it doesn't need an object ...
Definition: TrainUnit.h:287
TInterface::PreviousTTEntryButtonClick
void __fastcall PreviousTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3452
TInterface::UserGraphicButton
TBitBtn * UserGraphicButton
Definition: InterfaceUnit.h:82
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:15187
TInterface::Text_Y
int Text_Y
as above for 'Y'
Definition: InterfaceUnit.h:1098
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:16861
TInterface::DeleteTTEntryButton
TButton * DeleteTTEntryButton
Definition: InterfaceUnit.h:133
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TInterface::ReselectUserGraphicClick
void __fastcall ReselectUserGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12406
TInterface::TTClockAdd1mButtonClick
void __fastcall TTClockAdd1mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12022
TInterface::SubMinsButton
TButton * SubMinsButton
Definition: InterfaceUnit.h:142
TInterface::SpeedButton66
TSpeedButton * SpeedButton66
Definition: InterfaceUnit.h:570
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6391
TInterface::ValidateTimetableButtonClick
void __fastcall ValidateTimetableButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4229
TInterface::UserGraphicMoveVPos
int UserGraphicMoveVPos
used to store the original user graphic 'H' & 'V' positions for use during moving
Definition: InterfaceUnit.h:1108
TInterface::SpeedButton98
TSpeedButton * SpeedButton98
Definition: InterfaceUnit.h:602
TActionVectorEntry::LocationName
AnsiString LocationName
Definition: TrainUnit.h:96
TInterface::LoadTimetableMenuItem
TMenuItem * LoadTimetableMenuItem
Definition: InterfaceUnit.h:413
TInterface::SpeedButton95
TSpeedButton * SpeedButton95
Definition: InterfaceUnit.h:599
TInterface::LocationNameButtonClick
void __fastcall LocationNameButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1134
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5161
TInterface::SaveMenuItem
TMenuItem * SaveMenuItem
Definition: InterfaceUnit.h:412
TInterface::GapSetting
@ GapSetting
Definition: InterfaceUnit.h:885
TTrain::TimeTimeLocArrived
bool TimeTimeLocArrived
indicates whether has arrived (true) or not when ActionVectorEntryPtr->FormatType == TimeTimeLoc
Definition: TrainUnit.h:294
TInterface::ShowHideTTButton
TBitBtn * ShowHideTTButton
Definition: InterfaceUnit.h:124
TInterface::ScreenDownButton
TBitBtn * ScreenDownButton
Definition: InterfaceUnit.h:252
TTrain::LeadEntryPos
int LeadEntryPos
Definition: TrainUnit.h:327
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:664
TTrainController::LateArrivals
int LateArrivals
Definition: TrainUnit.h:768
TInterface::DeleteOnePrefDirButton
TBitBtn * DeleteOnePrefDirButton
Definition: InterfaceUnit.h:117
TInterface::PauseEntryTTClockSpeed
float PauseEntryTTClockSpeed
rate at which the timetable clock runs on entry to the adjust routine - to restore if cancelled
Definition: InterfaceUnit.h:1039
TTrainController::ReplotTrains
void ReplotTrains(int Caller, TDisplay *Disp)
plot all trains on the display
Definition: TrainUnit.cpp:8303
TInterface::MetreVariableLabel
TLabel * MetreVariableLabel
Definition: InterfaceUnit.h:103
TInterface::AllEntriesTTListBoxTopPosition
int AllEntriesTTListBoxTopPosition
stores the TopIndex property when keys are used to select items in the TT edit panel
Definition: InterfaceUnit.h:1058
TInterface::SigImagePanel
TPanel * SigImagePanel
new at v2.3.0 for handed signals
Definition: InterfaceUnit.h:387
TTrain::FloatingTimetableString
AnsiString FloatingTimetableString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the timetable.
Definition: TrainUnit.cpp:6592
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:644
TInterface::CPGenFileButtonClick
void __fastcall CPGenFileButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12503
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:16084
TInterface::TTClockAdd10mButtonClick
void __fastcall TTClockAdd10mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12002
TRailGraphics::SpeedBut73GrndBlackGlyph
Graphics::TBitmap * SpeedBut73GrndBlackGlyph
Definition: GraphicUnit.h:1058
TTrain::AValue
double AValue
this is a useful shorthand value in calculating speeds and transit times in SetTrainMovementValues [=...
Definition: TrainUnit.h:373
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6886
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:2711
TTrainController::WriteTrainsToImage
void WriteTrainsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click) to write all trains to the image file.
Definition: TrainUnit.cpp:8318
TInterface::SpeedButton30
TSpeedButton * SpeedButton30
Definition: InterfaceUnit.h:534
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:130
TInterface::TTClockSpeedLabel
TLabel * TTClockSpeedLabel
Definition: InterfaceUnit.h:329
TTrack::FourAspectBuild
@ FourAspectBuild
Definition: TrackUnit.h:757
TInterface::SpeedButton146
TSpeedButton * SpeedButton146
Definition: InterfaceUnit.h:650
TTrainController::OpTimeToActMultiMapIterator
TOpTimeToActMultiMapIterator OpTimeToActMultiMapIterator
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:803
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:540
TInterface::NewEntryInPreparationFlag
bool NewEntryInPreparationFlag
true when a new timetable entry is being prepared in the timetable editor
Definition: InterfaceUnit.h:957
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TInterface::OAPanelLabel
TLabel * OAPanelLabel
Definition: InterfaceUnit.h:334
TInterface::GetVersion
UnicodeString GetVersion()
determined automatically from the project options 'Version Info'
Definition: InterfaceUnit.cpp:812
TInterface::OneEntryTimetableContents
AnsiString OneEntryTimetableContents
the current text in the large right hand timetable edit window
Definition: InterfaceUnit.h:914
TInterface::SelectRect
TRect SelectRect
the rectangle in HLoc & VLoc terms set in Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1141
TTrain::ZeroPowerNoJoinedByMessage
bool ZeroPowerNoJoinedByMessage
Definition: TrainUnit.h:303
TInterface::LocationNameComboBox
TComboBox * LocationNameComboBox
the combobox that lists location names
Definition: InterfaceUnit.h:173
TInterface::ValidateTimetableKeyFlag
bool ValidateTimetableKeyFlag
Definition: InterfaceUnit.h:1029
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:662
TInterface::ExitOperationButton
TBitBtn * ExitOperationButton
Definition: InterfaceUnit.h:203
TTrain::CalcTimeToAct
float CalcTimeToAct(int Caller)
new v2.2.0 for operator action panel. Calculates the time left for operator action to avoid unnecessa...
Definition: TrainUnit.cpp:7693
TInterface::TTLabel6
TLabel * TTLabel6
Definition: InterfaceUnit.h:344
TInterface::SpeedButton97
TSpeedButton * SpeedButton97
Definition: InterfaceUnit.h:601
TTrainController::SaveSessionContinuationAutoSigEntries
void SaveSessionContinuationAutoSigEntries(int Caller, std::ofstream &SessionFile)
save ContinuationAutoSigEntries to a session file
Definition: TrainUnit.cpp:14203
TInterface::SignalStopImage
TImage * SignalStopImage
Definition: InterfaceUnit.h:265
TInterface::SpeedButton13
TSpeedButton * SpeedButton13
Definition: InterfaceUnit.h:517
TInterface::OutputLog9
TLabel * OutputLog9
Definition: InterfaceUnit.h:300
TInterface::SetCaption
void SetCaption(int Caller)
Sets the railway and timetable titles at the top of the screen.
Definition: InterfaceUnit.cpp:15852
TInterface::SpeedButton27
TSpeedButton * SpeedButton27
Definition: InterfaceUnit.h:531
TOnePrefDir::ExternalClearPrefDirAnd4MultiMap
void ExternalClearPrefDirAnd4MultiMap()
Empty the existing preferred direction vector & map - for use by other classes.
Definition: TrackUnit.h:1287
TInterface::SetInitialPrefDirModeEditMenu
void SetInitialPrefDirModeEditMenu()
Enables or disables the initial Edit mode submenu items in PrefDir mode.
Definition: InterfaceUnit.cpp:18591
TInterface::MainScreenMouseMove
void __fastcall MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7247
TInterface::DistanceContinuing
@ DistanceContinuing
Definition: InterfaceUnit.h:885
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:565
TInterface::CutTTEntryKeyFlag
bool CutTTEntryKeyFlag
Definition: InterfaceUnit.h:1023
TInterface::SigsOnLeftImage2
TImage * SigsOnLeftImage2
Definition: InterfaceUnit.h:281
TInterface::ChainEdit
TEdit * ChainEdit
Definition: InterfaceUnit.h:99
TInterface::SpeedButton109
TSpeedButton * SpeedButton109
Definition: InterfaceUnit.h:613
TInterface::CPAtLocCheckBox
TCheckBox * CPAtLocCheckBox
Definition: InterfaceUnit.h:244
TInterface::PasteTTEntryButtonClick
void __fastcall PasteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3778
TInterface::SpeedButton100
TSpeedButton * SpeedButton100
Definition: InterfaceUnit.h:604
TInterface::TestFunction
void TestFunction()
Called for diagnostic purposes when keys CTRL ALT 4 pressed.
Definition: InterfaceUnit.cpp:18691
TInterface::ExportTTKeyFlag
bool ExportTTKeyFlag
Definition: InterfaceUnit.h:1033
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:10482
TTrain::FirstHalfMove
bool FirstHalfMove
true when the train is on the first half of an element when it displays as fully on two elements....
Definition: TrainUnit.h:349
TInterface::MovingTrainPresentOnFlashingRoute
bool MovingTrainPresentOnFlashingRoute(int Caller)
Examines a flashing route (i.e. one being set) and returns true if a moving train is detected on it a...
Definition: InterfaceUnit.cpp:12985
TInterface::Level2TrackMode
enum TInterface::TLevel2TrackMode Level2TrackMode
TInterface::SpeedButton65
TSpeedButton * SpeedButton65
Definition: InterfaceUnit.h:569
TInterface::DeleteTTEntryKeyFlag
bool DeleteTTEntryKeyFlag
Definition: InterfaceUnit.h:1025
TTrainController::LatePasses
int LatePasses
Definition: TrainUnit.h:770
TInterface::SaveRailwayBaseModeButton
TBitBtn * SaveRailwayBaseModeButton
Save button at the top left hand corner of the screen when no mode is selected.
Definition: InterfaceUnit.h:59
TInterface::SelectBiDirPrefDirsMenuItem
TMenuItem * SelectBiDirPrefDirsMenuItem
Definition: InterfaceUnit.h:440
TInterface::UserGraphicReselectPanel
TPanel * UserGraphicReselectPanel
Definition: InterfaceUnit.h:483
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:98
TInterface::RotLeftMenuItem
TMenuItem * RotLeftMenuItem
Definition: InterfaceUnit.h:476
TInterface::TTClockxQuarterButtonClick
void __fastcall TTClockxQuarterButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11926
TTrainController::SSHigh
bool SSHigh
Definition: TrainUnit.h:743
TInterface::TextOrUserGraphicGridVal
int TextOrUserGraphicGridVal
stores the text alignment grid value, cycles forwards through 1, 2, 4, 8 & 16 each time the text grid...
Definition: InterfaceUnit.h:1100
TimeLoc
@ TimeLoc
Definition: TrainUnit.h:62
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:210
TInterface::FileMenu
TMenuItem * FileMenu
Definition: InterfaceUnit.h:409
TTrainController::AvHoursIntValue
int AvHoursIntValue
Input in MTBFEditBox in timetable hours, min value is 1 and max is 10,000. Here because performance f...
Definition: TrainUnit.h:788
TTrainController::CrashedTrains
int CrashedTrains
Definition: TrainUnit.h:763
TInterface::OutputLog3MouseDown
void __fastcall OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:11191
TInterface::SpeedConversionPanel
TPanel * SpeedConversionPanel
Definition: InterfaceUnit.h:106
TTrainController::TTEditPanelVisible
bool TTEditPanelVisible
new at v2.6.0 so potential error message only shows in TTEdit mode
Definition: TrainUnit.h:741
TTrain::LogAction
void LogAction(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionType ActionType, AnsiString LocationName, TDateTime TimetableNonRepeatTime, bool Warning)
Send a message to the performance log and performance file, and if the message is flagged as a warnin...
Definition: TrainUnit.cpp:4796
TInterface::SpeedButton22
TSpeedButton * SpeedButton22
Definition: InterfaceUnit.h:526
TTextHandler::SaveText
void SaveText(int Caller, std::ofstream &VecFile)
save the railway's text to VecFile
Definition: TextUnit.cpp:319
TTrain::StoppedAtSignal
bool StoppedAtSignal
Definition: TrainUnit.h:432
TInterface::SpeedButton130
TSpeedButton * SpeedButton130
Definition: InterfaceUnit.h:634
TTrack::GetGapHLoc
int GetGapHLoc()
Definition: TrackUnit.h:760
TInterface::ResetDefaultLengthButton
TBitBtn * ResetDefaultLengthButton
Definition: InterfaceUnit.h:78
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:139
TInterface::PauseEntryRestartTime
double PauseEntryRestartTime
time value of the timetable restart time (as a double) on entry to pause mode
Definition: InterfaceUnit.h:1036
TInterface::SelectBiDirPrefDirsMenuItemClick
void __fastcall SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9689
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4136
TInterface::SigsOnRightImage2
TImage * SigsOnRightImage2
Definition: InterfaceUnit.h:283
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:703
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4093
TInterface::AddTrack
@ AddTrack
Definition: InterfaceUnit.h:885
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1670
TInterface::ClearAllMenuItem
TMenuItem * ClearAllMenuItem
Definition: InterfaceUnit.h:416
TTrainController::THCandTrainPosParam
std::pair< AnsiString, int > THCandTrainPosParam
Definition: TrainUnit.h:714
TInterface::SaveImageNoGridMenuItem
TMenuItem * SaveImageNoGridMenuItem
Definition: InterfaceUnit.h:451
TInterface::SelectMenuItemClick
void __fastcall SelectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8926
TRailGraphics::SpeedBut74NormBlackGlyph
Graphics::TBitmap * SpeedBut74NormBlackGlyph
Definition: GraphicUnit.h:1051
TInterface::StartY
int StartY
the mouse position in terms of pixels when an item of text is being selected for moving
Definition: InterfaceUnit.h:1092
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:63
TInterface::UpdateOperatorActionPanel
void UpdateOperatorActionPanel(int Caller)
Called every 5 secs to update the panel (if visible)
Definition: InterfaceUnit.cpp:18789
TInterface::TextBoxKeyPress
void __fastcall TextBoxKeyPress(TObject *Sender, char &Key)
Definition: InterfaceUnit.cpp:1094
TInterface::SaveTimetableToSessionFile
bool SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
Called during a session save to save the current timetable in the session file, true if successful.
Definition: InterfaceUnit.cpp:16817
TInterface::SpeedButton71
TSpeedButton * SpeedButton71
Definition: InterfaceUnit.h:575
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:6637
TTrain::OpTimeToAct
float OpTimeToAct
in minutes: new at v2.2.0 for operator time to act panel. Calculated in UpdateTrain,...
Definition: TrainUnit.h:402
TInterface::DeleteAllPrefDirButtonClick
void __fastcall DeleteAllPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1936
Platform
@ Platform
Definition: TrackUnit.h:63
TInterface::RlyFile
bool RlyFile
indicates that a loaded railway file is ready for operation, i.e. is a valid .rly file
Definition: InterfaceUnit.h:969
TInterface::RestartSessionOperMode
@ RestartSessionOperMode
Definition: InterfaceUnit.h:855
TInterface::PreferredRouteFlag
bool PreferredRouteFlag
used to select either ConvertAndAddPreferredRouteSearchVector or ConvertAndAddNonPreferredRouteSearch...
Definition: InterfaceUnit.h:965
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:668
TInterface::TextMoveHPos
int TextMoveHPos
Definition: InterfaceUnit.h:1104
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4118
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:640
TInterface::PowerTopLabel
TLabel * PowerTopLabel
Definition: InterfaceUnit.h:188
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:679
TInterface::SpeedButton129
TSpeedButton * SpeedButton129
Definition: InterfaceUnit.h:633
TInterface::RepairFailedTrainMenuItem
TMenuItem * RepairFailedTrainMenuItem
Definition: InterfaceUnit.h:478
TUtilities::CheckAndCompareFileString
bool CheckAndCompareFileString(std::ifstream &InFile, AnsiString InString)
checks that the value is a string ('0' or CR accepted as delimiters) and is the same as InString,...
Definition: Utilities.cpp:413
TInterface::CutTTEntryButton
TButton * CutTTEntryButton
Definition: InterfaceUnit.h:131
TInterface::AZOrderKeyFlag
bool AZOrderKeyFlag
Definition: InterfaceUnit.h:1027
TInterface::MileEdit
TEdit * MileEdit
Definition: InterfaceUnit.h:98
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1193
TInterface::TTClockx8ButtonClick
void __fastcall TTClockx8ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11850
TInterface::SetLevel2OperMode
void SetLevel2OperMode(int Caller)
Sets the Level2OperMode user mode, using the Level2OperMode variable to determine the mode.
Definition: InterfaceUnit.cpp:14214
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:8630
TInterface::RestoreTTButton
TButton * RestoreTTButton
Definition: InterfaceUnit.h:147
TTrain::TimetableFinished
bool TimetableFinished
set when there are no more timetable actions
Definition: TrainUnit.h:369
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1484
TInterface::EraseLocationNameText
bool EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
Erase a location name (providing it exists in LocationNameMultiMap) from TextVector,...
Definition: InterfaceUnit.cpp:18633
TInterface::PrefDirKey
TImage * PrefDirKey
information panel displayed when setting preferred directions
Definition: InterfaceUnit.h:270
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:14448
TActionVectorEntry::Command
AnsiString Command
Definition: TrainUnit.h:96
TInterface::SpeedButton138
TSpeedButton * SpeedButton138
Definition: InterfaceUnit.h:642
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:705
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:147
TInterface::DeleteAllPrefDirButton
TBitBtn * DeleteAllPrefDirButton
Definition: InterfaceUnit.h:118
TInterface::SpeedButton117
TSpeedButton * SpeedButton117
Definition: InterfaceUnit.h:621
TTrain::SignallerStoppingFlag
bool SignallerStoppingFlag
set when the signaller stop command has been given
Definition: TrainUnit.h:361
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:141
TInterface::SpeedButton39
TSpeedButton * SpeedButton39
Definition: InterfaceUnit.h:543
TTrack::BuildBasicElementFromSpeedTag
TTrackElement BuildBasicElementFromSpeedTag(int Caller, int SpeedTag)
Return a basic track element from the SpeedTag new at v2.2.0 - needed because Interface doesn't have ...
Definition: TrackUnit.h:812
TInterface::TTStartTimeBox
TEdit * TTStartTimeBox
edit box that displays the timetable start time
Definition: InterfaceUnit.h:171
TInterface::AddPrefDirButtonClick
void __fastcall AddPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1909
TInterface::ShiftKey
bool ShiftKey
true when the SHIFT key is pressed (see also CtrlKey)
Definition: InterfaceUnit.h:983
TTrainController::SigSLow
bool SigSLow
Message flags in TT checks to stop being given twice.
Definition: TrainUnit.h:743
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:527
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:5676
TInterface::AddMinsButtonClick
void __fastcall AddMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3511
RemoveTrain
@ RemoveTrain
Definition: TrainUnit.h:50
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3205
TInterface::FontButtonClick
void __fastcall FontButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1840
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:98
TInterface::SigAspectButtonClick
void __fastcall SigAspectButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1801
TInterface::SetLevel2TrackMode
void SetLevel2TrackMode(int Caller)
Sets the Level2TrackMode user mode, using the Level2TrackMode variable to determine the mode.
Definition: InterfaceUnit.cpp:13589
TTrainController::SetWarningFlags
void SetWarningFlags(int Caller)
This sets all the warning flags (CrashWarning, DerailWarning etc) to their required states after a se...
Definition: TrainUnit.cpp:17286
TInterface::None
@ None
Definition: InterfaceUnit.h:890
TInterface::SpeedButton87
TSpeedButton * SpeedButton87
Definition: InterfaceUnit.h:591
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:111
TInterface::FormClose
void __fastcall FormClose(TObject *Sender, TCloseAction &Action)
Definition: InterfaceUnit.cpp:10596
TInterface::SigAspectButton
TBitBtn * SigAspectButton
Definition: InterfaceUnit.h:75
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:9955
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:650
TInterface::PreviousTTEntryKeyFlag
bool PreviousTTEntryKeyFlag
Definition: InterfaceUnit.h:1018
TInterface::CPEditDepRange
TEdit * CPEditDepRange
Definition: InterfaceUnit.h:246
TInterface::SpeedButton127
TSpeedButton * SpeedButton127
Definition: InterfaceUnit.h:631
TTrainController::TotEarlyPassMins
float TotEarlyPassMins
Definition: TrainUnit.h:757
TTrainController::OpTimeToActMultiMap
TOpTimeToActMultiMap OpTimeToActMultiMap
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:801
TInterface::SelectBitmapMouseLocY
int SelectBitmapMouseLocY
see above
Definition: InterfaceUnit.h:1082
TTrain::BrakeRate
double BrakeRate
the current train brake rate
Definition: TrainUnit.h:391
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:147
TTrack::GapFlashFlag
bool GapFlashFlag
true when a pair of connected gaps is flashing
Definition: TrackUnit.h:648
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:536
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TInterface::StartX
int StartX
Definition: InterfaceUnit.h:1092
TrainUnit.h
TTrack::LevelCrossingBarrierUpFlashDuration
float LevelCrossingBarrierUpFlashDuration
duration of the flash period when level crossing closing to trains
Definition: TrackUnit.h:666
TTrainController::IncorrectExits
int IncorrectExits
Definition: TrainUnit.h:767
TUtilities::SetLocaleResultOK
bool SetLocaleResultOK
flag to indicate whether the call to setlocale() in InterfaceUnit.cpp succeeded or not
Definition: Utilities.h:42
TInterface::SelectLengthsFlag
bool SelectLengthsFlag
true when 'Set lengths &/or speeds' selected in the 'Edit' menu
Definition: InterfaceUnit.h:979
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:87
TRailGraphics::LockedRouteCancelPtr
Graphics::TBitmap * LockedRouteCancelPtr[10]
for locked route cancel graphic, 1 for each of 8 links, 0 & 5 included as for direction
Definition: GraphicUnit.h:1037
TInterface::TrackOKButton
TBitBtn * TrackOKButton
Definition: InterfaceUnit.h:65
TInterface::SpeedButton23
TSpeedButton * SpeedButton23
Definition: InterfaceUnit.h:527
TInterface::RailwayTitle
AnsiString RailwayTitle
Definition: InterfaceUnit.h:918
TDisplay::Rectangle
void Rectangle(int Caller, int HPos, int VPos, TColor Col, int Size, int Width)
Plot a rectangle at the defined position with colour Col & size defined by Size.
Definition: DisplayUnit.cpp:152
TInterface::SpeedButton20
TSpeedButton * SpeedButton20
Definition: InterfaceUnit.h:524
TInterface::CheckInterface
bool CheckInterface(int Caller, std::ifstream &SessionFile)
Check the interface part of a session file & return false for error, called during SessionFileIntegri...
Definition: InterfaceUnit.cpp:16583
TInterface::PreStart
@ PreStart
Definition: InterfaceUnit.h:877
AboutForm
TAboutForm * AboutForm
Definition: AboutUnit.cpp:47
TInterface::SpeedButton137
TSpeedButton * SpeedButton137
Definition: InterfaceUnit.h:641
TInterface::ExitTTModeButton
TBitBtn * ExitTTModeButton
Definition: InterfaceUnit.h:125
TTrain::SetTrainMovementValues
void SetTrainMovementValues(int Caller, int TrackVectorPosition, int EntryPos)
Calculates train speeds and times for the element that the train is about to enter....
Definition: TrainUnit.cpp:3301
TActionVectorEntry::Warning
bool Warning
if set triggers an alert in the warning panel when the action is reached
Definition: TrainUnit.h:100
TInterface::OverallSpeedLimit
int OverallSpeedLimit
and the overall speed limit, if the speed limits vary across the selection the value is set to -1
Definition: InterfaceUnit.h:1070
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:10416
TInterface::SpeedButton78
TSpeedButton * SpeedButton78
Definition: InterfaceUnit.h:582
TRailGraphics::SpeedBut75GrndBlackGlyph
Graphics::TBitmap * SpeedBut75GrndBlackGlyph
Definition: GraphicUnit.h:1060
TTrainDataEntry::ServiceReference
AnsiString ServiceReference
Definition: TrainUnit.h:179
TInterface::PowerEditBox
TEdit * PowerEditBox
Definition: InterfaceUnit.h:187
TInterface::TimetableHandler
void TimetableHandler()
Called during timetable editing whenever a change is made to the timetable, sets all the timetable bu...
Definition: InterfaceUnit.cpp:5190
TTrain::SignallerChangeTrainDirection
void SignallerChangeTrainDirection(int Caller)
Unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd.
Definition: TrainUnit.cpp:6365
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:250
TInterface::CancelSelectionMenuItem
TMenuItem * CancelSelectionMenuItem
Definition: InterfaceUnit.h:441
TTrain::ZeroPowerNoRearSplitMessage
bool ZeroPowerNoRearSplitMessage
Definition: TrainUnit.h:301
TInterface::SpeedButton68
TSpeedButton * SpeedButton68
Definition: InterfaceUnit.h:572
TInterface::LoadSession
void LoadSession(int Caller)
Load a session file.
Definition: InterfaceUnit.cpp:16204
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:17131
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TInterface::SigRouteStartMarker
TGraphicElement * SigRouteStartMarker
Definition: InterfaceUnit.h:1124
TInterface::SetGapsButtonClick
void __fastcall SetGapsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1035
TInterface::SignallerControlStopMenuItemClick
void __fastcall SignallerControlStopMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10272
TInterface::PrefDirSelecting
@ PrefDirSelecting
Definition: InterfaceUnit.h:881
TInterface::TimetableDialog
TOpenDialog * TimetableDialog
Definition: InterfaceUnit.h:490
TInterface::MissedTicks
unsigned int MissedTicks
missed clock ticks
Definition: InterfaceUnit.h:1056
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:9984
TInterface::MoveTTEntryUpButton
TButton * MoveTTEntryUpButton
Definition: InterfaceUnit.h:134
TInterface::SigPrefConsecButton
TBitBtn * SigPrefConsecButton
Definition: InterfaceUnit.h:196
TInterface::RotateMenuItem
TMenuItem * RotateMenuItem
Definition: InterfaceUnit.h:436
TInterface::SpeedButton33
TSpeedButton * SpeedButton33
Definition: InterfaceUnit.h:537
TInterface::TTClockxSixteenthButtonClick
void __fastcall TTClockxSixteenthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11963
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:586
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:505
TUtilities::Clock2Stopped
bool Clock2Stopped
when true the main loop - Interface->ClockTimer2 - is stopped
Definition: Utilities.h:38
TTrainController::MRSHigh
bool MRSHigh
Definition: TrainUnit.h:743
TInterface::FlipMenuItem
TMenuItem * FlipMenuItem
Definition: InterfaceUnit.h:434
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:5578
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:156
TInterface::SessionFileIntegrityCheck
bool SessionFileIntegrityCheck(int Caller, AnsiString FileName)
Checks session file integrity prior to loading, true for success.
Definition: InterfaceUnit.cpp:17313
TInterface::TrainFailedImage
TImage * TrainFailedImage
Definition: InterfaceUnit.h:480
TTrain::NotInService
bool NotInService
Definition: TrainUnit.h:433
TInterface::RotLeftMenuItemClick
void __fastcall RotLeftMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9433
TInterface::SpeedButton14
TSpeedButton * SpeedButton14
Definition: InterfaceUnit.h:518
TInterface::ExitTrackButton
TBitBtn * ExitTrackButton
Definition: InterfaceUnit.h:76
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:642
TInterface::SpeedButton110
TSpeedButton * SpeedButton110
Definition: InterfaceUnit.h:614
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TInterface::OutputLog10
TLabel * OutputLog10
Definition: InterfaceUnit.h:301
TInterface::SESSION_DIR_NAME
static const UnicodeString SESSION_DIR_NAME
Definition: InterfaceUnit.h:869
TInterface::PasteTTEntryKeyFlag
bool PasteTTEntryKeyFlag
Definition: InterfaceUnit.h:1024
TInterface::FileChangedFlag
bool FileChangedFlag
true when a loaded railway file has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:945
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:141
TInterface::CutTTEntryButtonClick
void __fastcall CutTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3704
TInterface::AutoSigsButtonClick
void __fastcall AutoSigsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2058
TRailGraphics::SpeedBut69GrndBlackGlyph
Graphics::TBitmap * SpeedBut69GrndBlackGlyph
Definition: GraphicUnit.h:1054
Signaller
@ Signaller
Definition: TrainUnit.h:56
TRailGraphics::bmRedRect
Graphics::TBitmap * bmRedRect
Definition: GraphicUnit.h:527
TInterface::SaveOperatingImageMenuItemClick
void __fastcall SaveOperatingImageMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2831
TRailGraphics::smYellow
Graphics::TBitmap * smYellow
Definition: GraphicUnit.h:887
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TInterface::ConstructRoute
TOneRoute * ConstructRoute
the route under construction
Definition: InterfaceUnit.h:1138
TInterface::SpeedButton118
TSpeedButton * SpeedButton118
Definition: InterfaceUnit.h:622
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:9311
Bridge
@ Bridge
Definition: TrackUnit.h:63
TInterface::DirOpenError
bool DirOpenError
true when one of the program subfolders doesn't already exist and can't be created
Definition: InterfaceUnit.h:939
TInterface::CutMenuItemClick
void __fastcall CutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9014
TInterface::SpeedButton38
TSpeedButton * SpeedButton38
Definition: InterfaceUnit.h:542
TInterface::ResetCurrentSpeedButton
void ResetCurrentSpeedButton(int Caller)
Resets the CurrentSpeedButton variable to zero and the 'Down' property to false.
Definition: InterfaceUnit.cpp:12974
TInterface::SpeedButton102
TSpeedButton * SpeedButton102
Definition: InterfaceUnit.h:606
TTrain::TimetableMaxRunningSpeed
double TimetableMaxRunningSpeed
the maximum train running speed when in timetable mode (see int SignallerMaxSpeed for signaller contr...
Definition: TrainUnit.h:383
TInterface::SpeedButton99
TSpeedButton * SpeedButton99
Definition: InterfaceUnit.h:603
clB0G0R0
#define clB0G0R0
Definition: GraphicUnit.h:36
TInterface::CPDeparturesCheckBox
TCheckBox * CPDeparturesCheckBox
Definition: InterfaceUnit.h:243
Buffers
@ Buffers
Definition: TrackUnit.h:63
TInterface::SelectGraphic
@ SelectGraphic
Definition: InterfaceUnit.h:885
TTextHandler::TextMove
void TextMove(int Caller, int HPosInput, int VPosInput, int &TextItem, int &TextMoveHPos, int &TextMoveVPos, bool &TextFoundFlag)
Definition: TextUnit.cpp:196
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
clFrontCodeTimetable
#define clFrontCodeTimetable
Definition: GraphicUnit.h:296
TTrack::UserGraphicPresentAtHV
bool UserGraphicPresentAtHV(int Caller, int HPos, int VPos, int &UGIVectorPos)
checks if a user graphic present
Definition: TrackUnit.h:738
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:10440
TInterface::ExitTTModeButtonClick
void __fastcall ExitTTModeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4601
TInterface::MirrorMenuItemClick
void __fastcall MirrorMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9108
TInterface::SpeedButton11
TSpeedButton * SpeedButton11
Definition: InterfaceUnit.h:515
TInterface::RouteNotStarted
@ RouteNotStarted
Definition: InterfaceUnit.h:890
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4031
TInterface::SaveImageAndGridMenuItem
TMenuItem * SaveImageAndGridMenuItem
Definition: InterfaceUnit.h:452
TInterface::SpeedButton48
TSpeedButton * SpeedButton48
Definition: InterfaceUnit.h:552
TInterface::WhiteBgndMenuItemClick
void __fastcall WhiteBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11340
TInterface::GetTrainIDOrContinuationPosition
bool GetTrainIDOrContinuationPosition(int Caller, int X, int Y, int &TrainID, int &ContinuationPos)
Used in actions due panel to identify the train or continuation.
Definition: InterfaceUnit.cpp:4859